[
  {
    "path": ".bowerrc",
    "content": "{\n    \"directory\" : \"vendor/bower\"\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "# yii console command\n/yii\n\n# phpstorm 项目文件\n.idea\n\n# netbeans 项目文件\nnbproject\n\n# zend studio for eclipse 项目文件\n.buildpath\n.project\n.settings\n\n# windows 缩略图换成\nThumbs.db\n\n# composer 供应商目录\n/vendor\n\n# composer 它本身是不需要的（客户端自行升级最新版）\ncomposer.phar\n\n# Mac DS_Store 文件\n.DS_Store\n\n# phpunit 它本身是不需要的\nphpunit.phar\n# 本地 phpunit 配置文件\n/phpunit.xml\n\n/docker-compose.yml\n/supervisord.log\n/supervisord.pid\n\n\n# database config\n/common/config/db-local.php\n\n# install lock file\ninstall.lock\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\r\nphp:\r\n  - 5.4\r\n  - 5.5\r\n  - 5.6\r\n\r\ninstall:\r\n  - travis_retry composer self-update && composer --version\r\n  - travis_retry composer global require \"fxp/composer-asset-plugin:~1.1.1\"\r\n  - export PATH=\"$HOME/.composer/vendor/bin:$PATH\"\r\n\r\nbefore_script: composer install --prefer-source\r\n\r\n#script: phpunit --configuration phpunit.xml.dist\r\n\r\ncache:\r\n  directories:\r\n    - vendor\r\n\r\n#matrix:\r\n#  allow_failures:\r\n#    - php: hhvm"
  },
  {
    "path": "Dockerfile",
    "content": "FROM dcb9/php-fpm:latest\n\nMAINTAINER Bob <bob@phpor.me>\n\nRUN apt-get update \\\n  && apt-get install -y --no-install-recommends git vim \\\n  && rm -rf /var/lib/apt/lists/*\n\n# http://serverfault.com/questions/599103/make-a-docker-application-write-to-stdout\nRUN ln -sf /dev/stdout /var/log/nginx/access.log \\\n  && ln -sf /dev/stderr /var/log/nginx/error.log \\\n  && mkdir /app\nWORKDIR /app\n\nENV COMPOSER_HOME /root/.composer\nENV PATH /root/.composer/vendor/bin:$PATH\nRUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \\\n  # add chinese image http://pkg.phpcomposer.com/\n  && composer config -g repositories.packagist composer http://packagist.phpcomposer.com \\\n  && /usr/local/bin/composer global require --prefer-source --no-interaction \"fxp/composer-asset-plugin\"\n\nCOPY docker-files/getyii.com.conf /etc/nginx/conf.d/\nRUN docker-php-ext-install mysqli pdo pdo_mysql \\\n  && rm -rf /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/example_ssl.conf\nCOPY . /app/\n\nRUN chmod 700 docker-files/run.sh init\n\nVOLUME [\"/root/.composer\", \"/app/vendor\"]\nCMD [\"docker-files/run.sh\"]\nEXPOSE 80\n"
  },
  {
    "path": "LICENSE.md",
    "content": "The Yii framework is free software. It is released under the terms of\nthe following BSD License.\n\nCopyright © 2008 by Yii Software LLC (http://www.yiisoft.com)\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in\n   the documentation and/or other materials provided with the\n   distribution.\n * Neither the name of Yii Software LLC nor the names of its\n   contributors may be used to endorse or promote products derived\n   from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\nFOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\nCOPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\nBUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "GetYii\n==================\n\n[![Latest Stable Version](https://poser.pugx.org/iiyii/getyii/v/stable)](https://packagist.org/packages/iiyii/getyii) \n[![Total Downloads](https://poser.pugx.org/iiyii/getyii/downloads)](https://packagist.org/packages/iiyii/getyii) \n[![Latest Unstable Version](https://poser.pugx.org/iiyii/getyii/v/unstable)](https://packagist.org/packages/iiyii/getyii) \n[![License](https://poser.pugx.org/iiyii/getyii/license)](https://packagist.org/packages/iiyii/getyii)\n\ncommunity for Yii2\n\n## 说明\n\n你现在看到的是全新版本的 GetYii 之前的版本我放在 V1 分支上面了，那个版本以后可能就不会更新了。\n「doc/images」文件夹里面有截图，你们可以看一下。\n\n全新的 GetYii 只专注于社区，现在基本功能已经 OK 了，以后我们会不断完善的。分享我们的 [trello 项目管理地址](https://trello.com/b/rsZAtG1Y/getyii)。\n\n## 项目搭建\n\n### 原始安装方法（推荐）\n\n1、首先你要安装 [Composer](http://www.yiiframework.com/doc-2.0/guide-start-installation.html#installing-via-composer)，然后你需要手动去新建一个数据库，比方说新建 `getyii` 数据库，如果想使用 emoji 表情的话，意见使用 `utf8mb4` 编码格式，不想用的话，\n建议使用 `utf8` 编码格式。\n\n```\ngit clone https://github.com/iiYii/getyii.git\ncd getyii\ncomposer install\nphp init\n```\n\n2、然后修改数据库配置文件的配置信息\n\n```\nvim common/config/db.php\n```\n\n再使用运行我写的安装程序（帮你生成数据库表和假数据）\n\n```\nphp yii install \n```\n\n或者直接执行数据库迁移工具生成数据库表\n\n```\nphp yii migrate \n```\n\n### composer 安装方法（可能不是最新的）\n\n1、首先你要安装 [Composer](http://www.yiiframework.com/doc-2.0/guide-start-installation.html#installing-via-composer)，然后你需要手动去新建一个数据库，比方说新建 `getyii` 数据库，如果想使用 emoji 表情的话，意见使用 `utf8mb4` 编码格式，不想用的话，\n建议使用 `utf8` 编码格式。\n\n```\ncomposer create-project --prefer-dist --stability=dev iiyii/getyii getyii\ncd getyii\nphp init\n```\n\n2、然后复制一份数据库配置，并且修改数据库配置，\n\n```\ncp common/config/db.php common/config/db-local.php\n```\n\n再使用运行我写的安装程序（帮你生成数据库表和假数据）\n\n```\nphp yii install \n```\n\n或者直接执行数据库迁移工具生成数据库表\n\n```\nphp yii migrate \n```\n\n### docker 搭建方法\n\n1. 安装好 docker 保证可以运行 docker 和 docker-compose 命令\n2. 克隆代码到你本地，并 cd 到相应目录\n3. 启动 getyii 应用\n\n$ cp docker-files/docker-compose-example.yml docker-compose.yml\n\n$ docker-compose up -d\n\n访问 getyii\n\n添加以下两个域名加到自己机器的 host 里面\n\n\t<your_docker_ip> <your_name>.dev.getyii.com 前台\n\t<your_docker_ip> <your_name>.dev.admin.getyii.com 后台\n\n### 用户相关\n\n1. 把 user 表中的某用户值 role 字段值改为20，即为前台管理员，目前可以给帖子加精华，不能登录后台。\n1. 把 user 表中的某用户值 role 字段值改为30，即为超级管理员，可登录后台。\n\n\n## 文档和手册\n\n1. [Yii2手册](http://book.getyii.com)\n2. [中文 Composer 手册](http://docs.phpcomposer.com/)\n\n\n## 安装遇到问题怎么办?\n\n建议在官网的[社区版块](http://www.getyii.com/topic/default/create)**新手提问**下面提问，我会抽空亲自回答。请最大可能的把问题描述清楚，以免浪费我们彼此的时间。\n\n## 交流群\n\n- Yii2 中国交流群：343188481\n- Get√Yii 开发者群：321493381\n\n## 捐赠\n\n![微信支付](https://raw.githubusercontent.com/iiYii/getyii/master/wechat-pay.png)\n![支付宝支付](https://raw.githubusercontent.com/iiYii/getyii/master/ali-pay.png)\n\n手机微信或者支付宝扫描上方二维码可向本项目捐款\n\n\n感谢以下这些朋友的资金支持，所得捐赠将用于改善网站服务器、购买开发/调试设备&工具。\n\n\n捐赠人    | 金额 | 时间 | 说明\n-------|------|------ | ------\n张**  | 1.00  | 2015年7月7日 | http://asjmtz.com/\n*作军  | 100.00 | 2015年08月07日 | dba-china\n树*  | 333.00 | 2015年09月11日 | http://www.21cnjy.com/\n*作军  | 300.00 | 2016年04月28日 | dba-china\n*勇  | 20.00 | 2017年05月31日 | http://www.fecshop.com/\n*勇  | 66.00 | 2017年12月21日 | http://www.fecshop.com/\n\n\n## 他们正在使用 GetYii\n\n- DBA-CHINA\n- [Fecshop 社区](http://www.fecshop.com/)\n\n## 感谢\n\n- 感谢 [Ruby-China](https://github.com/ruby-china/ruby-china) 的开源代码。\n- 感谢 [PHPHub](https://github.com/summerblue/phphub) 的开源代码。\n- 感谢 [huajuan](https://github.com/callmez/huajuan) 的开源代码。\n- 最后再感谢一下女朋友的支持 <(▰˘◡˘▰)>。\n\nPS:\n\n如果你暂时无法使用 `composer` 的话，访问链接: <http://pan.baidu.com/s/1eQnsn7s> 密码: ux6c 下载 zip 文件解压就可以用了。然后你要做的是：\n\n- 新建数据库导入 getyii-2015-11-3.sql 数据库\n- 修改 `common\\config\\db-local.php` 文件的数据库配置\n- 默认用户名是`admin`，密码是`123456`\n"
  },
  {
    "path": "backend/assets/AppAsset.php",
    "content": "<?php\n/**\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\nnamespace backend\\assets;\n\nuse yii\\web\\AssetBundle;\n\n/**\n * @author Qiang Xue <qiang.xue@gmail.com>\n * @since 2.0\n */\nclass AppAsset extends AssetBundle\n{\n    public $basePath = '@webroot';\n    public $baseUrl = '@web';\n    public $css = [\n        'css/site.css',\n    ];\n    public $js = [\n    ];\n    public $depends = [\n        'yii\\web\\YiiAsset',\n        'yii\\bootstrap\\BootstrapAsset',\n    ];\n}\n"
  },
  {
    "path": "backend/config/.gitignore",
    "content": "main-local.php\nparams-local.php"
  },
  {
    "path": "backend/config/bootstrap.php",
    "content": "<?php\n"
  },
  {
    "path": "backend/config/main.php",
    "content": "<?php\n$params = array_merge(\n    require(__DIR__ . '/../../common/config/params.php'),\n    require(__DIR__ . '/../../common/config/params-local.php'),\n    require(__DIR__ . '/params.php'),\n    require(__DIR__ . '/params-local.php')\n);\n\nreturn [\n    'id' => 'app-backend',\n    'basePath' => dirname(__DIR__),\n    'controllerNamespace' => 'backend\\controllers',\n    'bootstrap' => ['log'],\n    'language' => 'zh-CN',\n    'modules' => [\n        'setting' => [\n            'class' => 'funson86\\setting\\Module',\n            'controllerNamespace' => 'funson86\\setting\\controllers',\n        ],\n        'backup' => [\n            'class' => 'yiier\\backup\\Module',\n        ],\n        'merit' => [\n            'class' => 'yiier\\merit\\Module',\n        ],\n    ],\n    'components' => [\n        'urlManager' => [\n            'enablePrettyUrl' => true,\n            'showScriptName' => false,\n            'rules' => [\n                '<controller:\\w+>/<action:\\w+>' => '<controller>/<action>',\n                '<controller:\\w+>/<action:\\w+>/<id:\\d+>' => '<controller>/<action>',\n            ],\n        ],\n        'user' => [\n            'identityClass' => 'common\\models\\User',\n            'enableAutoLogin' => true,\n        ],\n        'errorHandler' => [\n            'errorAction' => 'site/error',\n        ],\n    ],\n    'params' => $params,\n];\n"
  },
  {
    "path": "backend/config/params.php",
    "content": "<?php\nreturn [\n    'adminEmail' => 'admin@example.com',\n];\n"
  },
  {
    "path": "backend/controllers/CenterController.php",
    "content": "<?php\r\nnamespace backend\\controllers;\r\n\r\nuse Yii;\r\nuse yii\\filters\\AccessControl;\r\nuse yii\\filters\\VerbFilter;\r\n/**\r\n * Site controller\r\n */\r\nclass CenterController extends Controller\r\n{\r\n    /**\r\n     * @inheritdoc\r\n     */\r\n    public $layout = 'center';\r\n\r\n\r\n    public function behaviors()\r\n    {\r\n        return [\r\n            'access' => [\r\n                'class' => AccessControl::className(),\r\n                'rules' => [\r\n                    [\r\n                        'actions' => ['login', 'error'],\r\n                        'allow' => true,\r\n                    ],\r\n                    [\r\n                        'actions' => ['index','test'],\r\n                        'allow' => true,\r\n                        'roles' => ['@'],\r\n                    ],\r\n                ],\r\n            ],\r\n            'verbs' => [\r\n                'class' => VerbFilter::className(),\r\n                'actions' => [\r\n                    'logout' => ['post'],\r\n                ],\r\n            ],\r\n        ];\r\n    }\r\n\r\n    /**\r\n     * @inheritdoc\r\n     */\r\n    public function actions()\r\n    {\r\n        return [\r\n            'error' => [\r\n                'class' => 'yii\\web\\ErrorAction',\r\n            ],\r\n        ];\r\n    }\r\n\r\n\r\n\r\n    public function actionIndex()\r\n    {\r\n        return $this->render('index');\r\n    }\r\n\r\n    public function actionTest()\r\n    {\r\n        return $this->render('index');\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "backend/controllers/Controller.php",
    "content": "<?php\n/**\n * author     : forecho <caizh@chexiu.cn>\n * createTime : 2016/3/10 14:39\n * description:\n */\n\nnamespace backend\\controllers;\n\nuse yii\\filters\\AccessControl;\nuse common\\models\\User;\nuse yii\\web\\ForbiddenHttpException;\n\nclass Controller extends \\yii\\web\\Controller\n{\n    public function behaviors()\n    {\n        return [\n            // 后台必须登录才能使用\n            'access' => [\n                'class' => AccessControl::className(),\n                'rules' => [\n                    [\n                        'allow' => true,\n                        'roles' => ['@'],\n                    ],\n                ],\n            ],\n        ];\n    }\n\n\n    /**\n     * @param \\yii\\base\\Action $action\n     * @return bool\n     * @throws \\yii\\web\\BadRequestHttpException\n     */\n    public function beforeAction($action)\n    {\n        if (parent::beforeAction($action)) {\n            $uniqueid = $action->controller->action->uniqueid;\n            if (!in_array($uniqueid, ['site/login', 'site/logout', 'site/error']) && !User::currUserIsSuperAdmin()) {\n                throw new ForbiddenHttpException;\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "backend/controllers/NavController.php",
    "content": "<?php\n\nnamespace backend\\controllers;\n\nuse Yii;\nuse common\\models\\Nav;\nuse yii\\data\\ActiveDataProvider;\nuse yii\\web\\NotFoundHttpException;\n\n/**\n * NavController implements the CRUD actions for Nav model.\n */\nclass NavController extends Controller\n{\n    /**\n     * Lists all Nav models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $dataProvider = new ActiveDataProvider([\n            'query' => Nav::find(),\n        ]);\n\n        return $this->render('index', [\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * Displays a single Nav model.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionView($id)\n    {\n        return $this->render('view', [\n            'model' => $this->findModel($id),\n        ]);\n    }\n\n    /**\n     * Creates a new Nav model.\n     * If creation is successful, the browser will be redirected to the 'view' page.\n     * @return mixed\n     */\n    public function actionCreate()\n    {\n        $model = new Nav();\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('create', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Updates an existing Nav model.\n     * If update is successful, the browser will be redirected to the 'view' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionUpdate($id)\n    {\n        $model = $this->findModel($id);\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Deletes an existing Nav model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the Nav model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return Nav the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = Nav::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}\n"
  },
  {
    "path": "backend/controllers/NavUrlController.php",
    "content": "<?php\n\nnamespace backend\\controllers;\n\nuse Yii;\nuse common\\models\\NavUrl;\nuse yii\\data\\ActiveDataProvider;\nuse yii\\web\\NotFoundHttpException;\n\n/**\n * NavUrlController implements the CRUD actions for NavUrl model.\n */\nclass NavUrlController extends Controller\n{\n\n    /**\n     * Lists all NavUrl models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $dataProvider = new ActiveDataProvider([\n            'query' => NavUrl::find(),\n        ]);\n\n        return $this->render('index', [\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * Displays a single NavUrl model.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionView($id)\n    {\n        return $this->render('view', [\n            'model' => $this->findModel($id),\n        ]);\n    }\n\n    /**\n     * Creates a new NavUrl model.\n     * If creation is successful, the browser will be redirected to the 'view' page.\n     * @return mixed\n     */\n    public function actionCreate()\n    {\n        $model = new NavUrl();\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('create', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Updates an existing NavUrl model.\n     * If update is successful, the browser will be redirected to the 'view' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionUpdate($id)\n    {\n        $model = $this->findModel($id);\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Deletes an existing NavUrl model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the NavUrl model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return NavUrl the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = NavUrl::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}\n"
  },
  {
    "path": "backend/controllers/PostController.php",
    "content": "<?php\n\nnamespace backend\\controllers;\n\nuse Yii;\nuse common\\models\\Post;\nuse backend\\models\\PostSearch;\nuse yii\\web\\NotFoundHttpException;\n\n/**\n * PostController implements the CRUD actions for Post model.\n */\nclass PostController extends Controller\n{\n    /**\n     * Lists all Post models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $searchModel = new PostSearch();\n        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);\n\n        return $this->render('index', [\n            'searchModel' => $searchModel,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * Displays a single Post model.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionView($id)\n    {\n        return $this->render('view', [\n            'model' => $this->findModel($id),\n        ]);\n    }\n\n    /**\n     * Creates a new Post model.\n     * If creation is successful, the browser will be redirected to the 'view' page.\n     * @return mixed\n     */\n    public function actionCreate()\n    {\n        $model = new Post();\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('create', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n\n    /**\n     * Updates an existing Post model.\n     * If update is successful, the browser will be redirected to the 'view' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionUpdate($id)\n    {\n        $model = $this->findModel($id);\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Deletes an existing Post model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the Post model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return Post the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = Post::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}\n"
  },
  {
    "path": "backend/controllers/PostMetaController.php",
    "content": "<?php\n\nnamespace backend\\controllers;\n\nuse Yii;\nuse common\\models\\PostMeta;\nuse common\\models\\PostMetaSearch;\nuse yii\\web\\NotFoundHttpException;\n\n/**\n * PostMetaController implements the CRUD actions for PostMeta model.\n */\nclass PostMetaController extends Controller\n{\n    /**\n     * Lists all PostMeta models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $searchModel = new PostMetaSearch();\n        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);\n\n        return $this->render('index', [\n            'searchModel' => $searchModel,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * Creates a new PostMeta model.\n     * If creation is successful, the browser will be redirected to the 'view' page.\n     * @return mixed\n     */\n    public function actionCreate()\n    {\n        $model = new PostMeta();\n        $model->order = 999;\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect('index');\n        } else {\n            return $this->render('create', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Updates an existing PostMeta model.\n     * If update is successful, the browser will be redirected to the 'view' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionUpdate($id)\n    {\n        $model = $this->findModel($id);\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect('index');\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Deletes an existing PostMeta model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the PostMeta model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return PostMeta the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = PostMeta::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}\n"
  },
  {
    "path": "backend/controllers/RightLinkController.php",
    "content": "<?php\n\nnamespace backend\\controllers;\n\nuse Yii;\nuse common\\models\\RightLink;\nuse backend\\models\\RightLinkSearch;\nuse yii\\web\\NotFoundHttpException;\n\n/**\n * RightLinkController implements the CRUD actions for RightLink model.\n */\nclass RightLinkController extends Controller\n{\n    /**\n     * Lists all RightLink models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $searchModel = new RightLinkSearch();\n        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);\n\n        return $this->render('index', [\n            'searchModel' => $searchModel,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * Displays a single RightLink model.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionView($id)\n    {\n        return $this->render('view', [\n            'model' => $this->findModel($id),\n        ]);\n    }\n\n    /**\n     * Creates a new RightLink model.\n     * If creation is successful, the browser will be redirected to the 'view' page.\n     * @return mixed\n     */\n    public function actionCreate()\n    {\n        $model = new RightLink();\n        $request = Yii::$app->request->post();\n        $request['RightLink']['created_user'] = Yii::$app->user->identity->username;\n\n        if ($model->load($request) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('create', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Updates an existing RightLink model.\n     * If update is successful, the browser will be redirected to the 'view' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionUpdate($id)\n    {\n        $model = $this->findModel($id);\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Deletes an existing RightLink model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the RightLink model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return RightLink the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = RightLink::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}"
  },
  {
    "path": "backend/controllers/SearchLogController.php",
    "content": "<?php\n\nnamespace backend\\controllers;\n\nuse Yii;\nuse common\\models\\SearchLog;\nuse backend\\models\\SearchLogSearch;\nuse yii\\web\\NotFoundHttpException;\n\n/**\n * SearchLogController implements the CRUD actions for SearchLog model.\n */\nclass SearchLogController extends Controller\n{\n    /**\n     * Lists all SearchLog models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $searchModel = new SearchLogSearch();\n        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);\n\n        return $this->render('index', [\n            'searchModel' => $searchModel,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * Deletes an existing SearchLog model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the SearchLog model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return SearchLog the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = SearchLog::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}\n"
  },
  {
    "path": "backend/controllers/SiteController.php",
    "content": "<?php\r\nnamespace backend\\controllers;\r\n\r\nuse Yii;\r\nuse yii\\filters\\AccessControl;\r\nuse common\\models\\LoginForm;\r\nuse yii\\filters\\VerbFilter;\r\n\r\n/**\r\n * Site controller\r\n */\r\nclass SiteController extends Controller\r\n{\r\n    /**\r\n     * @inheritdoc\r\n     */\r\n    public function behaviors()\r\n    {\r\n        return [\r\n            'access' => [\r\n                'class' => AccessControl::className(),\r\n                'rules' => [\r\n                    [\r\n                        'actions' => ['login', 'error'],\r\n                        'allow' => true,\r\n                    ],\r\n                    [\r\n                        'actions' => ['logout', 'index'],\r\n                        'allow' => true,\r\n                        'roles' => ['@'],\r\n                    ],\r\n                ],\r\n            ],\r\n            'verbs' => [\r\n                'class' => VerbFilter::className(),\r\n                'actions' => [\r\n                    'logout' => ['post'],\r\n                ],\r\n            ],\r\n        ];\r\n    }\r\n\r\n    /**\r\n     * @param \\yii\\base\\Action $action\r\n     * @return bool\r\n     * @throws \\yii\\web\\BadRequestHttpException\r\n     */\r\n    public function beforeAction($action)\r\n    {\r\n        if (parent::beforeAction($action)) {\r\n            if ($action->id == 'error' && Yii::$app->user->isGuest) {\r\n                $this->layout = 'main-login';\r\n            }\r\n            return true;\r\n        } else {\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @inheritdoc\r\n     */\r\n    public function actions()\r\n    {\r\n        return [\r\n            'error' => [\r\n                'class' => 'yii\\web\\ErrorAction',\r\n            ],\r\n        ];\r\n    }\r\n\r\n    public function actionIndex()\r\n    {\r\n        return $this->render('index');\r\n    }\r\n\r\n    public function actionLogin()\r\n    {\r\n        if (!\\Yii::$app->user->isGuest) {\r\n            return $this->goHome();\r\n        }\r\n\r\n        $model = new LoginForm();\r\n        if ($model->load(Yii::$app->request->post()) && $model->loginAdmin()) {\r\n            return $this->goBack();\r\n        } else {\r\n            $data['model'] = $model;\r\n            return $this->render('login', $data);\r\n        }\r\n    }\r\n\r\n    public function actionLogout()\r\n    {\r\n        Yii::$app->user->logout();\r\n\r\n        return $this->goHome();\r\n    }\r\n}\r\n"
  },
  {
    "path": "backend/controllers/UserController.php",
    "content": "<?php\n\nnamespace backend\\controllers;\n\nuse Yii;\nuse common\\models\\User;\nuse common\\models\\UserSearch;\nuse yii\\web\\NotFoundHttpException;\n\n/**\n * UserController implements the CRUD actions for User model.\n */\nclass UserController extends Controller\n{\n    /**\n     * Lists all User models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $searchModel = new UserSearch();\n        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);\n\n        return $this->render('index', [\n            'searchModel' => $searchModel,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * Displays a single User model.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionView($id)\n    {\n        return $this->render('view', [\n            'model' => $this->findModel($id),\n        ]);\n    }\n\n    /**\n     * Creates a new User model.\n     * If creation is successful, the browser will be redirected to the 'view' page.\n     * @return mixed\n     */\n    public function actionCreate()\n    {\n        $model = new User();\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('create', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Updates an existing User model.\n     * If update is successful, the browser will be redirected to the 'view' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionUpdate($id)\n    {\n        $model = $this->findModel($id);\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['view', 'id' => $model->id]);\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * Deletes an existing User model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the User model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return User the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = User::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}\n"
  },
  {
    "path": "backend/models/.gitkeep",
    "content": "*\n"
  },
  {
    "path": "backend/models/PostSearch.php",
    "content": "<?php\n\nnamespace backend\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\nuse common\\models\\Post;\n\n/**\n * PostSearch represents the model behind the search form about `common\\Models\\Post`.\n */\nclass PostSearch extends Post\n{\n    public $category_name;\n    public $username;\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id', 'post_meta_id', 'user_id', 'view_count', 'comment_count', 'favorite_count', 'like_count', 'thanks_count', 'hate_count', 'status', 'order', 'created_at', 'updated_at'], 'integer'],\n            [['type', 'title', 'author', 'excerpt', 'image', 'content', 'tags', 'category_name', 'username'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * @param $params\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = Post::find()->joinWith(['category', 'user']);\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n            'pagination' => [\n                'pageSize' => 20,\n            ],\n            'sort' => ['defaultOrder' => [\n                'order' => SORT_ASC,\n                'updated_at' => SORT_DESC,\n            ]]\n        ]);\n\n        $dataProvider->sort->attributes['category_name'] = [\n            'asc' => ['name' => SORT_ASC],\n            'desc' => ['name' => SORT_DESC],\n        ];\n        $dataProvider->sort->attributes['username'] = [\n            'asc' => ['username' => SORT_ASC],\n            'desc' => ['username' => SORT_DESC],\n        ];\n\n        if (!($this->load($params) && $this->validate())) {\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'post_meta_id' => $this->post_meta_id,\n            'user_id' => $this->user_id,\n            'view_count' => $this->view_count,\n            'comment_count' => $this->comment_count,\n            'favorite_count' => $this->favorite_count,\n            'like_count' => $this->like_count,\n            'thanks_count' => $this->thanks_count,\n            'hate_count' => $this->hate_count,\n            Post::tableName() . '.status' => $this->status,\n            'order' => $this->order,\n            'created_at' => $this->created_at,\n            'updated_at' => $this->updated_at,\n        ]);\n\n        $query->andFilterWhere(['like', Post::tableName() . '.type', $this->type])\n            ->andFilterWhere(['like', 'title', $this->title])\n            ->andFilterWhere(['like', 'author', $this->author])\n            ->andFilterWhere(['like', 'excerpt', $this->excerpt])\n            ->andFilterWhere(['like', 'image', $this->image])\n            ->andFilterWhere(['like', 'content', $this->content])\n            ->andFilterWhere(['like', 'tags', $this->tags])\n            ->andFilterWhere(['like', 'name', $this->category_name])\n            ->andFilterWhere(['like', 'username', $this->username]);\n\n        return $dataProvider;\n    }\n}\n"
  },
  {
    "path": "backend/models/RightLinkSearch.php",
    "content": "<?php\n\nnamespace backend\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\nuse common\\models\\RightLink;\n\n/**\n * RightLinkSearch represents the model behind the search form about `common\\models\\RightLink`.\n */\nclass RightLinkSearch extends RightLink\n{\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id', 'type', 'created_at', 'updated_at'], 'integer'],\n            [['title', 'url', 'image', 'content', 'created_user'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * Creates data provider instance with search query applied\n     *\n     * @param array $params\n     *\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = RightLink::find();\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n        ]);\n\n        $this->load($params);\n\n        if (!$this->validate()) {\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'type' => $this->type,\n            'created_at' => $this->created_at,\n            'updated_at' => $this->updated_at,\n        ]);\n\n        $query->andFilterWhere(['like', 'title', $this->title])\n            ->andFilterWhere(['like', 'url', $this->url])\n            ->andFilterWhere(['like', 'image', $this->image])\n            ->andFilterWhere(['like', 'content', $this->content])\n            ->andFilterWhere(['like', 'created_user', $this->created_user]);\n\n        return $dataProvider;\n    }\n}"
  },
  {
    "path": "backend/models/SearchLogSearch.php",
    "content": "<?php\n\nnamespace backend\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\nuse common\\models\\SearchLog;\n\n/**\n * SearchLogSearch represents the model behind the search form about `common\\models\\SearchLog`.\n */\nclass SearchLogSearch extends SearchLog\n{\n    public $username;\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id', 'user_id', 'created_at'], 'integer'],\n            [['keyword', 'username'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * Creates data provider instance with search query applied\n     *\n     * @param array $params\n     *\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = SearchLog::find()->joinWith('user');\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n        ]);\n\n        $dataProvider->sort->attributes['username'] = [\n            'asc' => ['username' => SORT_ASC],\n            'desc' => ['username' => SORT_DESC],\n        ];\n\n        $this->load($params);\n\n        if (!$this->validate()) {\n            // uncomment the following line if you do not want to return any records when validation fails\n            // $query->where('0=1');\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'user_id' => $this->user_id,\n            'created_at' => $this->created_at,\n        ]);\n\n        $query->andFilterWhere(['like', 'keyword', $this->keyword])\n            ->andFilterWhere(['like', 'username', $this->username]);;\n\n        return $dataProvider;\n    }\n}\n"
  },
  {
    "path": "backend/models/User.php",
    "content": "<?php\r\n\r\nnamespace app\\models;\r\n\r\nuse Yii;\r\n\r\n/**\r\n * This is the model class for table \"{{%user}}\".\r\n *\r\n * @property integer $id\r\n * @property string $username\r\n * @property string $auth_key\r\n * @property string $password_hash\r\n * @property string $password_reset_token\r\n * @property string $email\r\n * @property integer $role\r\n * @property integer $status\r\n * @property integer $created_at\r\n * @property integer $updated_at\r\n */\r\nclass User extends \\yii\\db\\ActiveRecord\r\n{\r\n    /**\r\n     * @inheritdoc\r\n     */\r\n    public static function tableName()\r\n    {\r\n        return '{{%user}}';\r\n    }\r\n\r\n    /**\r\n     * @inheritdoc\r\n     */\r\n    public function rules()\r\n    {\r\n        return [\r\n            [['username', 'auth_key', 'password_hash', 'email', 'created_at', 'updated_at'], 'required'],\r\n            [['role', 'status', 'created_at', 'updated_at'], 'integer'],\r\n            [['username', 'password_hash', 'password_reset_token', 'email'], 'string', 'max' => 255],\r\n            [['auth_key'], 'string', 'max' => 32]\r\n        ];\r\n    }\r\n\r\n    /**\r\n     * @inheritdoc\r\n     */\r\n    public function attributeLabels()\r\n    {\r\n        return [\r\n            'id' => Yii::t('app', 'ID'),\r\n            'username' => Yii::t('app', 'Username'),\r\n            'auth_key' => Yii::t('app', 'Auth Key'),\r\n            'password_hash' => Yii::t('app', 'Password Hash'),\r\n            'password_reset_token' => Yii::t('app', 'Password Reset Token'),\r\n            'email' => Yii::t('app', 'Email'),\r\n            'role' => Yii::t('app', 'Role'),\r\n            'status' => Yii::t('app', 'Status'),\r\n            'created_at' => Yii::t('app', 'Created At'),\r\n            'updated_at' => Yii::t('app', 'Updated At'),\r\n        ];\r\n    }\r\n}\r\n"
  },
  {
    "path": "backend/runtime/.gitignore",
    "content": "*\n!.gitignore"
  },
  {
    "path": "backend/views/layouts/content.php",
    "content": "<?php\nuse yii\\widgets\\Breadcrumbs;\nuse dmstr\\widgets\\Alert;\n\n?>\n<div class=\"content-wrapper\">\n    <section class=\"content-header\">\n        <?php if (isset($this->blocks['content-header'])) { ?>\n            <h1><?= $this->blocks['content-header'] ?></h1>\n        <?php } else { ?>\n            <h1>\n                <?php\n                if ($this->title !== null) {\n                    echo \\yii\\helpers\\Html::encode($this->title);\n                } else {\n                    echo \\yii\\helpers\\Inflector::camel2words(\n                        \\yii\\helpers\\Inflector::id2camel($this->context->module->id)\n                    );\n                    echo ($this->context->module->id !== \\Yii::$app->id) ? '<small>Module</small>' : '';\n                } ?>\n            </h1>\n        <?php } ?>\n\n        <?=\n        Breadcrumbs::widget(\n            [\n                'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],\n            ]\n        ) ?>\n    </section>\n\n    <section class=\"content\">\n        <?= Alert::widget() ?>\n        <?= $content ?>\n    </section>\n</div>\n\n<footer class=\"main-footer\">\n    <div class=\"pull-right hidden-xs\">\n        <b>Version</b> 2.0\n    </div>\n    <strong>Copyright &copy; 2014-2015 <a href=\"http://almsaeedstudio.com\">Almsaeed Studio</a>.</strong> All rights\n    reserved.\n</footer>\n\n<!-- Add the sidebar's background. This div must be placed\n     immediately after the control sidebar -->\n<div class='control-sidebar-bg'></div>"
  },
  {
    "path": "backend/views/layouts/header.php",
    "content": "<?php\nuse yii\\helpers\\Html;\n\n/* @var $this \\yii\\web\\View */\n/* @var $content string */\n?>\n\n<header class=\"main-header\">\n\n    <?= Html::a('<span class=\"logo-mini\">APP</span><span class=\"logo-lg\">' . Yii::$app->setting->get('siteName') . '</span>', Yii::$app->homeUrl, ['class' => 'logo']) ?>\n\n    <nav class=\"navbar navbar-static-top\" role=\"navigation\">\n\n        <a href=\"#\" class=\"sidebar-toggle\" data-toggle=\"push-menu\" role=\"button\">\n            <span class=\"sr-only\">Toggle navigation</span>\n        </a>\n\n        <div class=\"navbar-custom-menu\">\n\n            <ul class=\"nav navbar-nav\">\n                <!-- User Account: style can be found in dropdown.less -->\n                <li>\n                    <?= Html::a(\n                        'Logout (' . Yii::$app->user->identity->username . ')',\n                        ['/site/logout'],\n                        ['data-method' => 'post', 'class' => 'btn btn-flat']\n                    ) ?>\n                </li>\n            </ul>\n        </div>\n    </nav>\n</header>\n"
  },
  {
    "path": "backend/views/layouts/left.php",
    "content": "<aside class=\"main-sidebar\">\n\n    <section class=\"sidebar\">\n\n        <!-- Sidebar user panel -->\n        <div class=\"user-panel\">\n            <div class=\"pull-left image\">\n                <img src=\"<?= $directoryAsset ?>/img/user2-160x160.jpg\" class=\"img-circle\" alt=\"User Image\"/>\n            </div>\n            <div class=\"pull-left info\">\n                <p><?= Yii::$app->user->identity->username ?></p>\n\n                <a href=\"#\"><i class=\"fa fa-circle text-success\"></i> Online</a>\n            </div>\n        </div>\n\n        <!-- search form -->\n        <form action=\"#\" method=\"get\" class=\"sidebar-form\">\n            <div class=\"input-group\">\n                <input type=\"text\" name=\"q\" class=\"form-control\" placeholder=\"Search...\"/>\n              <span class=\"input-group-btn\">\n                <button type='submit' name='search' id='search-btn' class=\"btn btn-flat\"><i class=\"fa fa-search\"></i>\n                </button>\n              </span>\n            </div>\n        </form>\n        <!-- /.search form -->\n\n        <?php\n            $debugMenu = [];\n            if (!YII_ENV_TEST) {\n                $debugMenu = [\n                    ['label' => 'Menu Yii2', 'options' => ['class' => 'header']],\n                    [\n                        'label' => 'Same tools',\n                        'icon' => 'fa fa-share',\n                        'url' => '#',\n                        'items' => [\n                            ['label' => 'Gii', 'icon' => 'file-code-o', 'url' => ['/gii']],\n                            ['label' => 'Debug', 'icon' => 'dashboard', 'url' => ['/debug']]\n                        ],\n                    ]\n                ];\n            }\n        ?>\n\n        <?= dmstr\\widgets\\Menu::widget(\n            [\n                'options' => ['class' => 'sidebar-menu tree','data-widget'=>'tree'],\n                'items' => array_merge([\n                    ['label' => 'Menu', 'options' => ['class' => 'header']],\n                    ['label' => '用户管理', 'icon' => 'users', 'url' => ['/user/index']],\n                    ['label' => '文章管理', 'icon' => 'comment-o', 'url' => ['/post/index']],\n                    ['label' => '分类管理', 'icon' => 'th-list', 'url' => ['/post-meta']],\n                    ['label' => '网站配置', 'icon' => 'cog', 'url' => ['/setting/default']],\n                    [\n                        'label' => '网站导航', 'url' => '#', 'icon' => 'share',\n                        'items' => [\n                            ['label' => '导航分类', 'icon' => 'plane', 'url' => ['/nav/index']],\n                            ['label' => '导航链接', 'icon' => 'plane', 'url' => ['/nav-url/index']],\n                        ]\n                    ],\n                    [\n                        'label' => '积分模块', 'url' => '#', 'icon' => 'share',\n                        'items' => [\n                            ['label' => '积分模板', 'icon' => 'money', 'url' => ['/merit/merit-template']],\n                            ['label' => '会员积分', 'icon' => 'money', 'url' => ['/merit/merit']],\n                            ['label' => '积分日志', 'icon' => 'money', 'url' => ['/merit/merit-log']],\n                        ]\n                    ],\n                    ['label' => '搜索日志', 'icon' => 'search', 'url' => ['/search-log/index']],\n                    ['label' => '右边栏设置', 'icon' => 'diamond', 'url' => ['/right-link/index']],\n                ], $debugMenu),\n            ]\n        ) ?>\n\n    </section>\n\n</aside>\n"
  },
  {
    "path": "backend/views/layouts/main-login.php",
    "content": "<?php\nuse backend\\assets\\AppAsset;\nuse yii\\helpers\\Html;\n\n/* @var $this \\yii\\web\\View */\n/* @var $content string */\n\ndmstr\\web\\AdminLteAsset::register($this);\n?>\n<?php $this->beginPage() ?>\n<!DOCTYPE html>\n<html lang=\"<?= Yii::$app->language ?>\">\n<head>\n    <meta charset=\"<?= Yii::$app->charset ?>\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <?= Html::csrfMetaTags() ?>\n    <title><?= Html::encode($this->title) ?></title>\n    <?php $this->head() ?>\n</head>\n<body class=\"login-page\">\n\n<?php $this->beginBody() ?>\n\n    <?= $content ?>\n\n<?php $this->endBody() ?>\n</body>\n</html>\n<?php $this->endPage() ?>\n"
  },
  {
    "path": "backend/views/layouts/main.php",
    "content": "<?php\nuse yii\\helpers\\Html;\n\n/* @var $this \\yii\\web\\View */\n/* @var $content string */\n\n\nif (Yii::$app->controller->action->id === 'login') { \n/**\n * Do not use this code in your template. Remove it. \n * Instead, use the code  $this->layout = '//main-login'; in your controller.\n */\n    echo $this->render(\n        'main-login',\n        ['content' => $content]\n    );\n} else {\n\n    if (class_exists('backend\\assets\\AppAsset')) {\n        backend\\assets\\AppAsset::register($this);\n    } else {\n        app\\assets\\AppAsset::register($this);\n    }\n\n    dmstr\\web\\AdminLteAsset::register($this);\n\n    $directoryAsset = Yii::$app->assetManager->getPublishedUrl('@vendor/almasaeed2010/adminlte/dist');\n    ?>\n    <?php $this->beginPage() ?>\n    <!DOCTYPE html>\n    <html lang=\"<?= Yii::$app->language ?>\">\n    <head>\n        <meta charset=\"<?= Yii::$app->charset ?>\"/>\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n        <?= Html::csrfMetaTags() ?>\n        <title><?= Html::encode(Yii::$app->setting->get('siteName')) ?></title>\n        <?php $this->head() ?>\n    </head>\n    <body class=\"hold-transition skin-blue sidebar-mini\">\n    <?php $this->beginBody() ?>\n    <div class=\"wrapper\">\n\n        <?= $this->render(\n            'header.php',\n            ['directoryAsset' => $directoryAsset]\n        ) ?>\n\n        <?= $this->render(\n            'left.php',\n            ['directoryAsset' => $directoryAsset]\n        )\n        ?>\n\n        <?= $this->render(\n            'content.php',\n            ['content' => $content, 'directoryAsset' => $directoryAsset]\n        ) ?>\n\n    </div>\n\n    <?php $this->endBody() ?>\n    </body>\n    </html>\n    <?php $this->endPage() ?>\n<?php } ?>\n"
  },
  {
    "path": "backend/views/nav/_form.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\Nav */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"nav-form\">\n\n    <?php $form = ActiveForm::begin(); ?>\n\n    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>\n\n    <?= $form->field($model, 'alias')->textInput(['maxlength' => true]) ?>\n\n    <?= $form->field($model, 'order')->textInput() ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav/create.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\Nav */\n\n$this->title = Yii::t('app', 'Create Nav');\n$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Navs'), 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"nav-create\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\grid\\GridView;\n\n/* @var $this yii\\web\\View */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = Yii::t('app', 'Navs');\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"nav-index\">\n\n    <p>\n        <?= Html::a(Yii::t('app', 'Create Nav'), ['create'], ['class' => 'btn btn-success']) ?>\n    </p>\n\n    <?= GridView::widget([\n        'dataProvider' => $dataProvider,\n        'columns' => [\n            ['class' => 'yii\\grid\\SerialColumn'],\n\n            'id',\n            'name',\n            'alias',\n            'order',\n            'created_at',\n            // 'updated_at',\n\n            ['class' => 'yii\\grid\\ActionColumn'],\n        ],\n    ]); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav/update.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\Nav */\n\n$this->title = Yii::t('app', 'Update {modelClass}: ', [\n    'modelClass' => 'Nav',\n]) . ' ' . $model->name;\n$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Navs'), 'url' => ['index']];\n$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];\n$this->params['breadcrumbs'][] = Yii::t('app', 'Update');\n?>\n<div class=\"nav-update\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav/view.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\DetailView;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\Nav */\n\n$this->title = $model->name;\n$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Navs'), 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"nav-view\">\n\n    <p>\n        <?= Html::a(Yii::t('app', 'Update'), ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>\n        <?= Html::a(Yii::t('app', 'Delete'), ['delete', 'id' => $model->id], [\n            'class' => 'btn btn-danger',\n            'data' => [\n                'confirm' => Yii::t('app', 'Are you sure you want to delete this item?'),\n                'method' => 'post',\n            ],\n        ]) ?>\n    </p>\n\n    <?= DetailView::widget([\n        'model' => $model,\n        'attributes' => [\n            'id',\n            'name',\n            'alias',\n            'order',\n            'created_at',\n            'updated_at',\n        ],\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav-url/_form.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\nuse common\\models\\Nav;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\NavUrl */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"nav-url-form\">\n\n    <?php $form = ActiveForm::begin(); ?>\n\n    <?= $form->field($model, 'nav_id')->dropDownList(Nav::getNavList()) ?>\n\n    <?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>\n\n    <?= $form->field($model, 'url')->textInput(['maxlength' => true]) ?>\n\n    <?= $form->field($model, 'description')->textInput(['maxlength' => true]) ?>\n\n    <?= $form->field($model, 'order')->textInput() ?>\n\n\n    <div class=\"form-group\">\n        <?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav-url/create.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\NavUrl */\n\n$this->title = Yii::t('app', 'Create Nav Url');\n$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Nav Urls'), 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"nav-url-create\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav-url/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\grid\\GridView;\n\n/* @var $this yii\\web\\View */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = Yii::t('app', 'Nav Urls');\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"nav-url-index\">\n\n    <p>\n        <?= Html::a(Yii::t('app', 'Create Nav Url'), ['create'], ['class' => 'btn btn-success']) ?>\n    </p>\n\n    <?= GridView::widget([\n        'dataProvider' => $dataProvider,\n        'columns' => [\n            ['class' => 'yii\\grid\\SerialColumn'],\n\n            'id',\n            'nav_id',\n            'title',\n            'url:url',\n            'description',\n            // 'order',\n            // 'user_id',\n            // 'created_at',\n            // 'updated_at',\n\n            ['class' => 'yii\\grid\\ActionColumn'],\n        ],\n    ]); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav-url/update.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\NavUrl */\n\n$this->title = Yii::t('app', 'Update {modelClass}: ', [\n    'modelClass' => 'Nav Url',\n]) . ' ' . $model->title;\n$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Nav Urls'), 'url' => ['index']];\n$this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]];\n$this->params['breadcrumbs'][] = Yii::t('app', 'Update');\n?>\n<div class=\"nav-url-update\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/nav-url/view.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\DetailView;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\NavUrl */\n\n$this->title = $model->title;\n$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Nav Urls'), 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"nav-url-view\">\n\n    <p>\n        <?= Html::a(Yii::t('app', 'Update'), ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>\n        <?= Html::a(Yii::t('app', 'Delete'), ['delete', 'id' => $model->id], [\n            'class' => 'btn btn-danger',\n            'data' => [\n                'confirm' => Yii::t('app', 'Are you sure you want to delete this item?'),\n                'method' => 'post',\n            ],\n        ]) ?>\n    </p>\n\n    <?= DetailView::widget([\n        'model' => $model,\n        'attributes' => [\n            'id',\n            'nav_id',\n            'title',\n            'url:url',\n            'description',\n            'order',\n            'user_id',\n            'created_at',\n            'updated_at',\n        ],\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post/_form.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\Post */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"post-form\">\n\n    <?php $form = ActiveForm::begin(); ?>\n\n    <?= $form->field($model, 'post_meta_id')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'user_id')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'title')->textInput(['maxlength' => 255]) ?>\n\n    <?= $form->field($model, 'author')->textInput(['maxlength' => 100]) ?>\n\n    <?= $form->field($model, 'excerpt')->textInput(['maxlength' => 255]) ?>\n\n    <?= $form->field($model, 'image')->textInput(['maxlength' => 255]) ?>\n\n    <?= $form->field($model, 'content')->textarea(['rows' => 6]) ?>\n\n    <?= $form->field($model, 'tags')->textInput(['maxlength' => 255]) ?>\n\n    <?= $form->field($model, 'view_count')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'comment_count')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'favorite_count')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'like_count')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'hate_count')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'status')->textInput() ?>\n\n    <?= $form->field($model, 'order')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'created_at')->textInput(['maxlength' => 11]) ?>\n\n    <?= $form->field($model, 'updated_at')->textInput(['maxlength' => 11]) ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post/_search.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\PostSearch */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"post-search\">\n\n    <?php $form = ActiveForm::begin([\n        'action' => ['index'],\n        'method' => 'get',\n    ]); ?>\n\n    <?= $form->field($model, 'id') ?>\n\n    <?= $form->field($model, 'post_meta_id') ?>\n\n    <?= $form->field($model, 'user_id') ?>\n\n    <?= $form->field($model, 'title') ?>\n\n    <?= $form->field($model, 'author') ?>\n\n    <?php // echo $form->field($model, 'excerpt') ?>\n\n    <?php // echo $form->field($model, 'image') ?>\n\n    <?php // echo $form->field($model, 'content') ?>\n\n    <?php // echo $form->field($model, 'tags') ?>\n\n    <?php // echo $form->field($model, 'view_count') ?>\n\n    <?php // echo $form->field($model, 'comment_count') ?>\n\n    <?php // echo $form->field($model, 'favorite_count') ?>\n\n    <?php // echo $form->field($model, 'like_count') ?>\n\n    <?php // echo $form->field($model, 'hate_count') ?>\n\n    <?php // echo $form->field($model, 'status') ?>\n\n    <?php // echo $form->field($model, 'order') ?>\n\n    <?php // echo $form->field($model, 'created_at') ?>\n\n    <?php // echo $form->field($model, 'updated_at') ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>\n        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post/create.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\Post */\n\n$this->title = 'Create Post';\n$this->params['breadcrumbs'][] = ['label' => 'Posts', 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"post-create\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\grid\\GridView;\nuse common\\models\\Post;\n\n/* @var $this yii\\web\\View */\n/* @var $searchModel common\\Models\\PostSearch */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = 'Posts';\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"post-index\">\n\n    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>\n\n    <p>\n        <?= Html::a('Create Post', ['create'], ['class' => 'btn btn-success']) ?>\n    </p>\n\n    <?= GridView::widget([\n        'dataProvider' => $dataProvider,\n        'filterModel' => $searchModel,\n        'columns' => [\n            [\n                'attribute' => 'id',\n                'options' => ['width' => '10px'],\n            ],\n            'title',\n            [\n                'attribute' => 'category_name',\n                'filter' => Html::activeTextInput($searchModel, 'category_name', ['class' => 'form-control']),\n                'format' => 'raw',\n                'value' => function ($data) {\n                    return $data->category['name'];\n                },\n            ],\n            [\n                'attribute' => 'username',\n                'filter' => Html::activeTextInput($searchModel, 'username', ['class' => 'form-control']),\n                'value' => function ($data) {\n                    return $data->user['username'];\n                },\n            ],\n//             'tags',\n            [\n                'attribute' => 'view_count',\n                'options' => ['width' => '10px'],\n            ],\n            [\n                'attribute' => 'comment_count',\n                'options' => ['width' => '10px'],\n            ],\n//            [\n//                'attribute' => 'favorite_count',\n//                'options' => ['width' => '10px'],\n//            ],\n//            [\n//                'attribute' => 'like_count',\n//                'options' => ['width' => '10px'],\n//            ],\n//            [\n//                'attribute' => 'hate_count',\n//                'options' => ['width' => '10px'],\n//            ],\n            [\n                'attribute' => 'order',\n                'options' => ['width' => '10px'],\n            ],\n            [\n                'class' => \\common\\grid\\EnumColumn::className(),\n                'attribute' => 'status',\n                'filter' => Post::getStatuses(),\n                'enum' => Post::getStatuses(),\n            ],\n            'updated_at:datetime',\n\n            ['class' => 'yii\\grid\\ActionColumn'],\n        ],\n    ]); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post/update.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\Post */\n\n$this->title = 'Update Post: ' . ' ' . $model->title;\n$this->params['breadcrumbs'][] = ['label' => 'Posts', 'url' => ['index']];\n$this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]];\n$this->params['breadcrumbs'][] = 'Update';\n?>\n<div class=\"post-update\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post/view.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\DetailView;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\Post */\n\n$this->title = $model->title;\n$this->params['breadcrumbs'][] = ['label' => 'Posts', 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"post-view\">\n\n    <p>\n        <?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>\n        <?= Html::a('Delete', ['delete', 'id' => $model->id], [\n            'class' => 'btn btn-danger',\n            'data' => [\n                'confirm' => 'Are you sure you want to delete this item?',\n                'method' => 'post',\n            ],\n        ]) ?>\n    </p>\n\n    <?= DetailView::widget([\n        'model' => $model,\n        'attributes' => [\n            'id',\n            'post_meta_id',\n            'user_id',\n            'title',\n            'author',\n            'excerpt',\n            'image',\n            'content:ntext',\n            'tags',\n            'view_count',\n            'comment_count',\n            'favorite_count',\n            'like_count',\n            'hate_count',\n            'status',\n            'order',\n            'created_at',\n            'updated_at',\n        ],\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post-meta/_form.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\PostMeta */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"post-meta-form\">\n\n    <?php $form = ActiveForm::begin(); ?>\n\n    <?= $form->field($model, 'name')->textInput(['maxlength' => 100]) ?>\n\n    <?= $form->field($model, 'parent')->dropDownList([0 => '根目录'] + $model->getParents()) ?>\n\n    <?= $form->field($model, 'alias')->textInput(['maxlength' => 32]) ?>\n\n    <?= $form->field($model, 'type')->dropDownList($model->types) ?>\n\n    <?= $form->field($model, 'description')->textarea(['row' => 6]) ?>\n\n    <?= $form->field($model, 'order')->textInput(['maxlength' => 11]) ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post-meta/_search.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\PostMetaSearch */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"post-meta-search\">\n\n    <?php $form = ActiveForm::begin([\n        'action' => ['index'],\n        'method' => 'get',\n    ]); ?>\n\n    <?= $form->field($model, 'name') ?>\n\n    <?= $form->field($model, 'type') ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>\n        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post-meta/create.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\PostMeta */\n\n$this->title = 'Create Post Meta';\n$this->params['breadcrumbs'][] = ['label' => 'Post Metas', 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"post-meta-create\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post-meta/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\grid\\GridView;\n\n/* @var $this yii\\web\\View */\n/* @var $searchModel common\\models\\PostMetaSearch */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = 'Post Metas';\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"post-meta-index\">\n\n    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>\n\n    <p>\n        <?= Html::a('Create Post Meta', ['create'], ['class' => 'btn btn-success']) ?>\n    </p>\n\n    <?= GridView::widget([\n        'dataProvider' => $dataProvider,\n        'filterModel' => $searchModel,\n        'columns' => [\n            ['class' => 'yii\\grid\\SerialColumn'],\n\n            'id',\n            'name',\n            'parent',\n            'alias',\n            'type',\n            'description',\n            // 'count',\n            // 'order',\n            // 'created_at',\n            // 'updated_at',\n\n            ['class' => 'yii\\grid\\ActionColumn'],\n        ],\n    ]); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post-meta/update.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\PostMeta */\n\n$this->title = 'Update Post Meta: ' . ' ' . $model->name;\n$this->params['breadcrumbs'][] = ['label' => 'Post Metas', 'url' => ['index']];\n$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]];\n$this->params['breadcrumbs'][] = 'Update';\n?>\n<div class=\"post-meta-update\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/post-meta/view.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\DetailView;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\PostMeta */\n\n$this->title = $model->name;\n$this->params['breadcrumbs'][] = ['label' => 'Post Metas', 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"post-meta-view\">\n\n    <p>\n        <?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>\n        <?= Html::a('Delete', ['delete', 'id' => $model->id], [\n            'class' => 'btn btn-danger',\n            'data' => [\n                'confirm' => 'Are you sure you want to delete this item?',\n                'method' => 'post',\n            ],\n        ]) ?>\n    </p>\n\n    <?= DetailView::widget([\n        'model' => $model,\n        'attributes' => [\n            'id',\n            'name',\n            'parent',\n            'alias',\n            'type',\n            'description',\n            'count',\n            'order',\n            'created_at',\n            'updated_at',\n        ],\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/right-link/_form.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\RightLink */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"right-link-form\">\n\n    <?php $form = ActiveForm::begin(); ?>\n\n    <?= $form->field($model, 'title')->textInput(['maxlength' => 255]) ?>\n\n    <?= $form->field($model, 'type')->dropDownList($model->getTypes()) ?>\n\n    <?= $form->field($model, 'url')->textInput(['maxlength' => 225]) ?>\n\n    <?= $form->field($model, 'image')->textInput(['maxlength' => 255]) ?>\n\n    <?= $form->field($model, 'content')->textarea(['row' => 10]) ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>"
  },
  {
    "path": "backend/views/right-link/_search.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model backend\\models\\RightLinkSearch */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"right-link-search\">\n\n    <?php $form = ActiveForm::begin([\n        'action' => ['index'],\n        'method' => 'get',\n    ]); ?>\n\n    <?= $form->field($model, 'id') ?>\n\n    <?= $form->field($model, 'title') ?>\n\n    <?= $form->field($model, 'url') ?>\n\n    <?= $form->field($model, 'image') ?>\n\n    <?= $form->field($model, 'content') ?>\n\n    <?php // echo $form->field($model, 'type') ?>\n\n    <?php // echo $form->field($model, 'created_user') ?>\n\n    <?php // echo $form->field($model, 'created_at') ?>\n\n    <?php // echo $form->field($model, 'updated_at') ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>\n        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>"
  },
  {
    "path": "backend/views/right-link/create.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\RightLink */\n\n$this->title = 'Create Right Link';\n$this->params['breadcrumbs'][] = ['label' => 'Right Links', 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"right-link-create\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>"
  },
  {
    "path": "backend/views/right-link/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\grid\\GridView;\n\n/* @var $this yii\\web\\View */\n/* @var $searchModel backend\\models\\RightLinkSearch */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = '右边栏设置';\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"right-link-index\">\n\n    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>\n\n    <p>\n        <?= Html::a('Create Right Link', ['create'], ['class' => 'btn btn-success']) ?>\n    </p>\n\n    <?= GridView::widget([\n        'dataProvider' => $dataProvider,\n        'filterModel' => $searchModel,\n        'columns' => [\n            ['class' => 'yii\\grid\\SerialColumn'],\n\n            'id',\n            'title',\n            'type',\n            'url:url',\n//            'image',\n//            'content',\n            // 'created_user',\n            // 'created_at',\n            // 'updated_at',\n\n            ['class' => 'yii\\grid\\ActionColumn'],\n        ],\n    ]); ?>\n\n</div>"
  },
  {
    "path": "backend/views/right-link/update.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\RightLink */\n\n$this->title = 'Update Right Link: ' . ' ' . $model->title;\n$this->params['breadcrumbs'][] = ['label' => 'Right Links', 'url' => ['index']];\n$this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]];\n$this->params['breadcrumbs'][] = 'Update';\n?>\n<div class=\"right-link-update\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>"
  },
  {
    "path": "backend/views/right-link/view.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\DetailView;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\RightLink */\n\n$this->title = $model->title;\n$this->params['breadcrumbs'][] = ['label' => 'Right Links', 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"right-link-view\">\n\n    <p>\n        <?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>\n        <?= Html::a('Delete', ['delete', 'id' => $model->id], [\n            'class' => 'btn btn-danger',\n            'data' => [\n                'confirm' => 'Are you sure you want to delete this item?',\n                'method' => 'post',\n            ],\n        ]) ?>\n    </p>\n\n    <?= DetailView::widget([\n        'model' => $model,\n        'attributes' => [\n            'id',\n            'title',\n            'url:url',\n            'image',\n            'content',\n            'type',\n            'created_user',\n            'created_at',\n            'updated_at',\n        ],\n    ]) ?>\n\n</div>"
  },
  {
    "path": "backend/views/search-log/_search.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model backend\\models\\SearchLogSearch */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"search-log-search\">\n\n    <?php $form = ActiveForm::begin([\n        'action' => ['index'],\n        'method' => 'get',\n    ]); ?>\n\n    <?= $form->field($model, 'id') ?>\n\n    <?= $form->field($model, 'user_id') ?>\n\n    <?= $form->field($model, 'keyword') ?>\n\n    <?= $form->field($model, 'created_at') ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>\n        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/search-log/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\grid\\GridView;\n\n/* @var $this yii\\web\\View */\n/* @var $searchModel backend\\models\\SearchLogSearch */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = 'Search Logs';\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"search-log-index\">\n\n    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>\n\n\n    <?= GridView::widget([\n        'dataProvider' => $dataProvider,\n        'filterModel' => $searchModel,\n        'columns' => [\n            ['class' => 'yii\\grid\\SerialColumn'],\n\n            [\n                'attribute' => 'username',\n                'filter' => Html::activeTextInput($searchModel, 'username', ['class' => 'form-control']),\n                'format' => 'raw',\n                'value' => function ($data) {\n                    return $data->user['username'];\n                },\n            ],\n            'keyword',\n            'created_at:datetime',\n\n            ['class' => 'yii\\grid\\ActionColumn', 'template' => '{delete}'],\n        ],\n    ]); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/site/error.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\n\n/* @var $this yii\\web\\View */\n/* @var $name string */\n/* @var $message string */\n/* @var $exception Exception */\n\n$this->title = $name;\n?>\n<!-- Main content -->\n<section class=\"content\">\n\n    <div class=\"error-page\">\n        <h2 class=\"headline text-info\"><i class=\"fa fa-warning text-yellow\"></i></h2>\n\n        <div class=\"error-content\">\n            <h3><?= $name ?></h3>\n\n            <p>\n                <?= nl2br(Html::encode($message)) ?>\n            </p>\n\n            <p>\n                The above error occurred while the Web server was processing your request.\n                Please contact us if you think this is a server error. Thank you.\n                Meanwhile, you may <a href='<?= Yii::$app->homeUrl ?>'>return to dashboard</a> or try using the search\n                form.\n            </p>\n\n            <form class='search-form'>\n                <div class='input-group'>\n                    <input type=\"text\" name=\"search\" class='form-control' placeholder=\"Search\"/>\n\n                    <div class=\"input-group-btn\">\n                        <button type=\"submit\" name=\"submit\" class=\"btn btn-primary\"><i class=\"fa fa-search\"></i>\n                        </button>\n                    </div>\n                </div>\n            </form>\n        </div>\n    </div>\n\n</section>\n"
  },
  {
    "path": "backend/views/site/index.php",
    "content": "<?php\n/* @var $this yii\\web\\View */\n\n$this->title = 'My Yii Application';\n?>\n<div class=\"site-index\">\n\n    <div class=\"jumbotron\">\n        <h1>Congratulations!</h1>\n\n        <p class=\"lead\">You have successfully created your Yii-powered application.</p>\n\n        <p><a class=\"btn btn-lg btn-success\" href=\"http://www.yiiframework.com\">Get started with Yii</a></p>\n    </div>\n\n    <div class=\"body-content\">\n\n        <div class=\"row\">\n            <div class=\"col-lg-4\">\n                <h2>Heading</h2>\n\n                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et\n                    dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip\n                    ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu\n                    fugiat nulla pariatur.</p>\n\n                <p><a class=\"btn btn-default\" href=\"http://www.yiiframework.com/doc/\">Yii Documentation &raquo;</a></p>\n            </div>\n            <div class=\"col-lg-4\">\n                <h2>Heading</h2>\n\n                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et\n                    dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip\n                    ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu\n                    fugiat nulla pariatur.</p>\n\n                <p><a class=\"btn btn-default\" href=\"http://www.yiiframework.com/forum/\">Yii Forum &raquo;</a></p>\n            </div>\n            <div class=\"col-lg-4\">\n                <h2>Heading</h2>\n\n                <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et\n                    dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip\n                    ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu\n                    fugiat nulla pariatur.</p>\n\n                <p><a class=\"btn btn-default\" href=\"http://www.yiiframework.com/extensions/\">Yii Extensions &raquo;</a></p>\n            </div>\n        </div>\n\n    </div>\n</div>\n"
  },
  {
    "path": "backend/views/site/login.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\bootstrap\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $form yii\\bootstrap\\ActiveForm */\n/* @var $model \\common\\models\\LoginForm */\n\n$this->title = Yii::t('backend', 'Sign in');\n\n$fieldOptions1 = [\n    'options' => ['class' => 'form-group has-feedback'],\n    'inputTemplate' => \"{input}<span class='glyphicon glyphicon-envelope form-control-feedback'></span>\"\n];\n\n$fieldOptions2 = [\n    'options' => ['class' => 'form-group has-feedback'],\n    'inputTemplate' => \"{input}<span class='glyphicon glyphicon-lock form-control-feedback'></span>\"\n];\n?>\n\n<div class=\"login-box\">\n    <div class=\"login-logo\">\n        <a href=\"#\"><b>Get</b>Yii</a>\n    </div>\n    <!-- /.login-logo -->\n    <div class=\"login-box-body\">\n        <p class=\"login-box-msg\"><?= $this->title ?></p>\n\n        <?php $form = ActiveForm::begin(['id' => 'login-form', 'enableClientValidation' => false]); ?>\n\n        <?= $form\n            ->field($model, 'username', $fieldOptions1)\n            ->label(false)\n            ->textInput(['placeholder' => $model->getAttributeLabel('username')]) ?>\n\n        <?= $form\n            ->field($model, 'password', $fieldOptions2)\n            ->label(false)\n            ->passwordInput(['placeholder' => $model->getAttributeLabel('password')]) ?>\n\n        <div class=\"row\">\n            <div class=\"col-xs-8\">\n                <?= $form->field($model, 'rememberMe')->checkbox() ?>\n            </div>\n            <!-- /.col -->\n            <div class=\"col-xs-4\">\n                <?= Html::submitButton(Yii::t('backend', 'Sign in'), ['class' => 'btn btn-primary btn-block btn-flat', 'name' => 'login-button']) ?>\n            </div>\n            <!-- /.col -->\n        </div>\n\n\n        <?php ActiveForm::end(); ?>\n\n    </div>\n    <!-- /.login-box-body -->\n</div><!-- /.login-box -->\n"
  },
  {
    "path": "backend/views/user/_form.php",
    "content": "<?php\n\nuse common\\models\\User;\nuse conquer\\select2\\Select2Widget;\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\User */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"user-form\">\n\n    <?php $form = ActiveForm::begin(); ?>\n\n    <?= $form->field($model, 'role')->widget(Select2Widget::classname(), [\n        'items' => ['' => '选择一个权限'] + User::getRoleList(),\n    ]); ?>\n\n    <?= $form->field($model, 'status')->widget(Select2Widget::classname(), [\n        'items' => ['' => '选择一个状态'] + User::getStatusList(),\n    ]); ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n</div>\n"
  },
  {
    "path": "backend/views/user/_search.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\UserSearch */\n/* @var $form yii\\widgets\\ActiveForm */\n?>\n\n<div class=\"user-search\">\n\n    <?php $form = ActiveForm::begin([\n        'action' => ['index'],\n        'method' => 'get',\n    ]); ?>\n\n    <?= $form->field($model, 'id') ?>\n\n    <?= $form->field($model, 'username') ?>\n\n    <?= $form->field($model, 'avatar') ?>\n\n    <?= $form->field($model, 'auth_key') ?>\n\n    <?= $form->field($model, 'password_hash') ?>\n\n    <?php // echo $form->field($model, 'password_reset_token') ?>\n\n    <?php // echo $form->field($model, 'email') ?>\n\n    <?php // echo $form->field($model, 'tagline') ?>\n\n    <?php // echo $form->field($model, 'role') ?>\n\n    <?php // echo $form->field($model, 'status') ?>\n\n    <?php // echo $form->field($model, 'created_at') ?>\n\n    <?php // echo $form->field($model, 'updated_at') ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>\n        <?= Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/user/index.php",
    "content": "<?php\n\nuse common\\models\\User;\nuse yii\\grid\\GridView;\n\n/* @var $this yii\\web\\View */\n/* @var $searchModel common\\models\\UserSearch */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = 'Users';\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"user-index\">\n\n    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>\n\n    <?= GridView::widget([\n        'dataProvider' => $dataProvider,\n        'filterModel' => $searchModel,\n        'columns' => [\n            ['class' => 'yii\\grid\\SerialColumn'],\n\n            'id',\n            'username',\n            'avatar',\n            // 'password_reset_token',\n            // 'email:email',\n            // 'tagline',\n             [\n                 'attribute' => 'role',\n                 'value' => function($model) {\n                     return User::getRole($model->role)['name'];\n                 },\n             ],\n            // 'status',\n             'created_at:datetime',\n             'updated_at:datetime',\n\n            ['class' => 'yii\\grid\\ActionColumn'],\n        ],\n    ]); ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/user/update.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\User */\n\n$this->title = 'Update User: ' . ' ' . $model->id;\n$this->params['breadcrumbs'][] = ['label' => 'Users', 'url' => ['index']];\n$this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]];\n$this->params['breadcrumbs'][] = 'Update';\n?>\n<div class=\"user-update\">\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/views/user/view.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\DetailView;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\User */\n\n$this->title = $model->id;\n$this->params['breadcrumbs'][] = ['label' => 'Users', 'url' => ['index']];\n$this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"user-view\">\n\n    <p>\n        <?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>\n        <?= Html::a('Delete', ['delete', 'id' => $model->id], [\n            'class' => 'btn btn-danger',\n            'data' => [\n                'confirm' => 'Are you sure you want to delete this item?',\n                'method' => 'post',\n            ],\n        ]) ?>\n    </p>\n\n    <?= DetailView::widget([\n        'model' => $model,\n        'attributes' => [\n            'id',\n            'username',\n            'avatar',\n            'auth_key',\n            'password_hash',\n            'password_reset_token',\n            'email:email',\n            'tagline',\n            'role',\n            'status',\n            'created_at',\n            'updated_at',\n        ],\n    ]) ?>\n\n</div>\n"
  },
  {
    "path": "backend/web/.gitignore",
    "content": "/index.php\n/index-test.php\n"
  },
  {
    "path": "backend/web/.htaccess",
    "content": "# use mod_rewrite for pretty URL support\nRewriteEngine on\n# If a directory or a file exists, use the request directly\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\n# Otherwise forward the request to index.php\nRewriteRule . index.php\n\n# 七牛云存储的回调会传送HTTP_AUTHORIZATION认证秘钥,一定要放在最rewrite的后面.防止影响\n# PHP在CGI模式下的认证信息的获取\n# RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]"
  },
  {
    "path": "backend/web/assets/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "backend/web/css/sb-admin-2.css",
    "content": "/*!\r\n * Start Bootstrap - SB Admin 2 Bootstrap Admin Theme (http://startbootstrap.com)\r\n * Code licensed under the Apache License v2.0.\r\n * For details, see http://www.apache.org/licenses/LICENSE-2.0.\r\n */\r\n\r\nbody {\r\n    background-color: #f8f8f8;\r\n}\r\n\r\n#wrapper {\r\n    width: 100%;\r\n}\r\n\r\n#page-wrapper {\r\n    padding: 0 15px;\r\n    min-height: 568px;\r\n    background-color: #fff;\r\n}\r\n\r\n@media(min-width:768px) {\r\n    #page-wrapper {\r\n        position: inherit;\r\n        margin: 52px 0 0 250px;\r\n        padding: 0 30px;\r\n        border-left: 1px solid #e7e7e7;\r\n    }\r\n}\r\n\r\n.navbar-top-links li {\r\n    display: inline-block;\r\n}\r\n\r\n.navbar-top-links li:last-child {\r\n    margin-right: 15px;\r\n}\r\n\r\n.navbar-top-links li a {\r\n    padding: 15px;\r\n    min-height: 50px;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li {\r\n    display: block;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li:last-child {\r\n    margin-right: 0;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li a {\r\n    padding: 3px 20px;\r\n    min-height: 0;\r\n}\r\n\r\n.navbar-top-links .dropdown-menu li a div {\r\n    white-space: normal;\r\n}\r\n\r\n.navbar-top-links .dropdown-messages,\r\n.navbar-top-links .dropdown-tasks,\r\n.navbar-top-links .dropdown-alerts {\r\n    width: 310px;\r\n    min-width: 0;\r\n}\r\n\r\n.navbar-top-links .dropdown-messages {\r\n    margin-left: 5px;\r\n}\r\n\r\n.navbar-top-links .dropdown-tasks {\r\n    margin-left: -59px;\r\n}\r\n\r\n.navbar-top-links .dropdown-alerts {\r\n    margin-left: -123px;\r\n}\r\n\r\n.navbar-top-links .dropdown-user {\r\n    right: 0;\r\n    left: auto;\r\n}\r\n\r\n.sidebar .sidebar-nav.navbar-collapse {\r\n    padding-right: 0;\r\n    padding-left: 0;\r\n}\r\n\r\n.sidebar .sidebar-search {\r\n    padding: 15px;\r\n}\r\n\r\n.sidebar ul li {\r\n    border-bottom: 1px solid #e7e7e7;\r\n}\r\n\r\n.sidebar ul li a.active {\r\n    background-color: #eee;\r\n}\r\n\r\n.sidebar .arrow {\r\n    float: right;\r\n}\r\n\r\n.sidebar .fa.arrow:before {\r\n    content: \"\\f104\";\r\n}\r\n\r\n.sidebar .active>a>.fa.arrow:before {\r\n    content: \"\\f107\";\r\n}\r\n\r\n.sidebar .nav-second-level li,\r\n.sidebar .nav-third-level li {\r\n    border-bottom: 0!important;\r\n}\r\n\r\n.sidebar .nav-second-level li a {\r\n    padding-left: 37px;\r\n}\r\n\r\n.sidebar .nav-third-level li a {\r\n    padding-left: 52px;\r\n}\r\n\r\n@media(min-width:768px) {\r\n    .sidebar {\r\n        z-index: 1;\r\n        position: absolute;\r\n        width: 250px;\r\n        margin-top: 51px;\r\n    }\r\n\r\n    .navbar-top-links .dropdown-messages,\r\n    .navbar-top-links .dropdown-tasks,\r\n    .navbar-top-links .dropdown-alerts {\r\n        margin-left: auto;\r\n    }\r\n}\r\n\r\n.btn-outline {\r\n    color: inherit;\r\n    background-color: transparent;\r\n    transition: all .5s;\r\n}\r\n\r\n.btn-primary.btn-outline {\r\n    color: #428bca;\r\n}\r\n\r\n.btn-success.btn-outline {\r\n    color: #5cb85c;\r\n}\r\n\r\n.btn-info.btn-outline {\r\n    color: #5bc0de;\r\n}\r\n\r\n.btn-warning.btn-outline {\r\n    color: #f0ad4e;\r\n}\r\n\r\n.btn-danger.btn-outline {\r\n    color: #d9534f;\r\n}\r\n\r\n.btn-primary.btn-outline:hover,\r\n.btn-success.btn-outline:hover,\r\n.btn-info.btn-outline:hover,\r\n.btn-warning.btn-outline:hover,\r\n.btn-danger.btn-outline:hover {\r\n    color: #fff;\r\n}\r\n\r\n.chat {\r\n    margin: 0;\r\n    padding: 0;\r\n    list-style: none;\r\n}\r\n\r\n.chat li {\r\n    margin-bottom: 10px;\r\n    padding-bottom: 5px;\r\n    border-bottom: 1px dotted #999;\r\n}\r\n\r\n.chat li.left .chat-body {\r\n    margin-left: 60px;\r\n}\r\n\r\n.chat li.right .chat-body {\r\n    margin-right: 60px;\r\n}\r\n\r\n.chat li .chat-body p {\r\n    margin: 0;\r\n}\r\n\r\n.panel .slidedown .glyphicon,\r\n.chat .glyphicon {\r\n    margin-right: 5px;\r\n}\r\n\r\n.chat-panel .panel-body {\r\n    height: 350px;\r\n    overflow-y: scroll;\r\n}\r\n\r\n.login-panel {\r\n    margin-top: 25%;\r\n}\r\n\r\n.flot-chart {\r\n    display: block;\r\n    height: 400px;\r\n}\r\n\r\n.flot-chart-content {\r\n    width: 100%;\r\n    height: 100%;\r\n}\r\n\r\ntable.dataTable thead .sorting,\r\ntable.dataTable thead .sorting_asc,\r\ntable.dataTable thead .sorting_desc,\r\ntable.dataTable thead .sorting_asc_disabled,\r\ntable.dataTable thead .sorting_desc_disabled {\r\n    background: 0 0;\r\n}\r\n\r\ntable.dataTable thead .sorting_asc:after {\r\n    content: \"\\f0de\";\r\n    float: right;\r\n    font-family: fontawesome;\r\n}\r\n\r\ntable.dataTable thead .sorting_desc:after {\r\n    content: \"\\f0dd\";\r\n    float: right;\r\n    font-family: fontawesome;\r\n}\r\n\r\ntable.dataTable thead .sorting:after {\r\n    content: \"\\f0dc\";\r\n    float: right;\r\n    font-family: fontawesome;\r\n    color: rgba(50,50,50,.5);\r\n}\r\n\r\n.btn-circle {\r\n    width: 30px;\r\n    height: 30px;\r\n    padding: 6px 0;\r\n    border-radius: 15px;\r\n    text-align: center;\r\n    font-size: 12px;\r\n    line-height: 1.428571429;\r\n}\r\n\r\n.btn-circle.btn-lg {\r\n    width: 50px;\r\n    height: 50px;\r\n    padding: 10px 16px;\r\n    border-radius: 25px;\r\n    font-size: 18px;\r\n    line-height: 1.33;\r\n}\r\n\r\n.btn-circle.btn-xl {\r\n    width: 70px;\r\n    height: 70px;\r\n    padding: 10px 16px;\r\n    border-radius: 35px;\r\n    font-size: 24px;\r\n    line-height: 1.33;\r\n}\r\n\r\n.show-grid [class^=col-] {\r\n    padding-top: 10px;\r\n    padding-bottom: 10px;\r\n    border: 1px solid #ddd;\r\n    background-color: #eee!important;\r\n}\r\n\r\n.show-grid {\r\n    margin: 15px 0;\r\n}\r\n\r\n.huge {\r\n    font-size: 40px;\r\n}\r\n\r\n.panel-green {\r\n    border-color: #5cb85c;\r\n}\r\n\r\n.panel-green .panel-heading {\r\n    border-color: #5cb85c;\r\n    color: #fff;\r\n    background-color: #5cb85c;\r\n}\r\n\r\n.panel-green a {\r\n    color: #5cb85c;\r\n}\r\n\r\n.panel-green a:hover {\r\n    color: #3d8b3d;\r\n}\r\n\r\n.panel-red {\r\n    border-color: #d9534f;\r\n}\r\n\r\n.panel-red .panel-heading {\r\n    border-color: #d9534f;\r\n    color: #fff;\r\n    background-color: #d9534f;\r\n}\r\n\r\n.panel-red a {\r\n    color: #d9534f;\r\n}\r\n\r\n.panel-red a:hover {\r\n    color: #b52b27;\r\n}\r\n\r\n.panel-yellow {\r\n    border-color: #f0ad4e;\r\n}\r\n\r\n.panel-yellow .panel-heading {\r\n    border-color: #f0ad4e;\r\n    color: #fff;\r\n    background-color: #f0ad4e;\r\n}\r\n\r\n.panel-yellow a {\r\n    color: #f0ad4e;\r\n}\r\n\r\n.panel-yellow a:hover {\r\n    color: #df8a13;\r\n}\r\n\r\n/*面包屑*/\r\n.breadcrumb {\r\n   background-color: #fff;\r\n    padding: 17px 0 0;\r\n}"
  },
  {
    "path": "backend/web/css/site.css",
    "content": "html,\nbody {\n    height: 100%;\n}\n\n.wrap {\n    min-height: 100%;\n    height: auto;\n    margin: 0 auto -60px;\n    padding: 0 0 60px;\n}\n\n.wrap > .container {\n    padding: 70px 15px 20px;\n}\n\n.footer {\n    height: 60px;\n    background-color: #f5f5f5;\n    border-top: 1px solid #ddd;\n    padding-top: 20px;\n}\n\n.jumbotron {\n    text-align: center;\n    background-color: transparent;\n}\n\n.jumbotron .btn {\n    font-size: 21px;\n    padding: 14px 24px;\n}\n\n.not-set {\n    color: #c55;\n    font-style: italic;\n}\n\n/* add sorting icons to gridview sort links */\na.asc:after, a.desc:after {\n    position: relative;\n    top: 1px;\n    display: inline-block;\n    font-family: 'Glyphicons Halflings';\n    font-style: normal;\n    font-weight: normal;\n    line-height: 1;\n    padding-left: 5px;\n}\n\na.asc:after {\n    content: /*\"\\e113\"*/ \"\\e151\";\n}\n\na.desc:after {\n    content: /*\"\\e114\"*/ \"\\e152\";\n}\n\n.sort-numerical a.asc:after {\n    content: \"\\e153\";\n}\n\n.sort-numerical a.desc:after {\n    content: \"\\e154\";\n}\n\n.sort-ordinal a.asc:after {\n    content: \"\\e155\";\n}\n\n.sort-ordinal a.desc:after {\n    content: \"\\e156\";\n}\n\n.grid-view th {\n    white-space: nowrap;\n}\n\n.hint-block {\n    display: block;\n    margin-top: 5px;\n    color: #999;\n}\n\n.error-summary {\n    color: #a94442;\n    background: #fdf7f7;\n    border-left: 3px solid #eed3d7;\n    padding: 10px 20px;\n    margin: 0 0 15px 0;\n}\n\n/*面包屑*/\n#page-wrapper {\n    margin: 52px 0 0 250px;\n}\n.breadcrumb {\n   background-color: #fff;\n    padding: 17px 0 0;\n}"
  },
  {
    "path": "backend/web/js/sb-admin-2.js",
    "content": "$(function() {\r\n\r\n    $('#side-menu').metisMenu();\r\n\r\n});\r\n\r\n//Loads the correct sidebar on window load,\r\n//collapses the sidebar on window resize.\r\n// Sets the min-height of #page-wrapper to window size\r\n$(function() {\r\n    $(window).bind(\"load resize\", function() {\r\n        topOffset = 50;\r\n        width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;\r\n        if (width < 768) {\r\n            $('div.navbar-collapse').addClass('collapse')\r\n            topOffset = 100; // 2-row-menu\r\n        } else {\r\n            $('div.navbar-collapse').removeClass('collapse')\r\n        }\r\n\r\n        height = (this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height;\r\n        height = height - topOffset;\r\n        if (height < 1) height = 1;\r\n        if (height > topOffset) {\r\n            $(\"#page-wrapper\").css(\"min-height\", (height) + \"px\");\r\n        }\r\n    })\r\n})\r\n"
  },
  {
    "path": "backend/web/robots.txt",
    "content": "User-Agent: *\nDisallow: /\n"
  },
  {
    "path": "common/assets/AtJs.php",
    "content": "<?php\nnamespace common\\assets;\n\nuse yii\\web\\AssetBundle;\n\n/**\n * @author forecho <caizhenghai@gmail.com>\n */\nclass AtJs extends AssetBundle\n{\n    public $sourcePath = '@bower/At.js/dist';\n\n    public $css = [\n        'css/jquery.atwho.min.css',\n    ];\n\n    public $js = [\n        'js/jquery.atwho.min.js',\n    ];\n}\n"
  },
  {
    "path": "common/assets/CaretJs.php",
    "content": "<?php\nnamespace common\\assets;\n\nuse yii\\web\\AssetBundle;\n\n/**\n * @author forecho <caizhenghai@gmail.com>\n */\nclass CaretJs extends AssetBundle\n{\n    public $sourcePath = '@bower/caret.js/dist';\n\n    public $css = [];\n\n    public $js = [\n        'jquery.caret.min.js',\n    ];\n}\n"
  },
  {
    "path": "common/assets/DropzoneJs.php",
    "content": "<?php\nnamespace common\\assets;\n\nuse yii\\web\\AssetBundle;\n\n/**\n * @author forecho <caizhenghai@gmail.com>\n */\nclass DropzoneJs extends AssetBundle\n{\n    public $sourcePath = '@vendor/enyo/dropzone/dist/min';\n\n    public $css = [\n        'dropzone.min.css',\n    ];\n\n    public $js = [\n        'dropzone.min.js',\n    ];\n}\n"
  },
  {
    "path": "common/components/AssetBundle.php",
    "content": "<?php\r\nnamespace common\\components;\r\n\r\nclass AssetBundle extends \\yii\\web\\AssetBundle\r\n{\r\n    public $publishOptions = [\r\n        'forceCopy' => YII_DEBUG // debug模式时强制拷贝\r\n    ];\r\n}"
  },
  {
    "path": "common/components/ComposerInstaller.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 16/8/7 上午10:44\n * description:\n */\n\nnamespace common\\components;\n\nuse yii\\composer\\Installer;\n\nclass ComposerInstaller extends Installer\n{\n    public static function initProject($event)\n    {\n    }\n}"
  },
  {
    "path": "common/components/Config.php",
    "content": "<?php\r\nnamespace common\\components;\r\n\r\nuse Yii;\r\nuse yii\\base\\Object;\r\nuse yii\\base\\InvalidCallException;\r\nuse yii\\base\\InvalidConfigException;\r\n\r\nclass Config extends Object\r\n{\r\n    protected $data;\r\n\r\n    /**\r\n     * model class 名,如果未指定初始数据, 会根据此值从model类中取数据\r\n     * @var string\r\n     */\r\n    public $loadModel;\r\n    /**\r\n     * 如果指定了loadModel, 缓存的键值,必须注意cache键值, 缓存的键值会经过md5加密, 未指定会使用loadModel代替\r\n     * @var string\r\n     */\r\n    private $_cacheKey;\r\n    /**\r\n     * 缓存时间, 如果为0表示永久缓存, false 表示不缓存\r\n     * @var int|bool\r\n     */\r\n    public $cacheTime = 3600;\r\n\r\n    public $autoSave = true;\r\n\r\n    /**\r\n     * 数据保存\r\n     * @var array\r\n     */\r\n    private $_data = [];\r\n\r\n    /**\r\n     * 被修改的设置键值(当需要触发保存设置时.可以从该设置中查询修改了的值然后保存)\r\n     * @var array\r\n     */\r\n    private $_changedDataKeys = [];\r\n\r\n    /**\r\n     * 从model类指定的存储介质中(数据库, 缓存数据库, nosql数据库等...)取数据\r\n     * @throws \\yii\\base\\InvalidConfigException\r\n     */\r\n    public function init()\r\n    {\r\n        if ($this->loadModel !== null) {\r\n            $loadModel = $this->loadModel;\r\n\r\n            if (!method_exists($loadModel, 'getData')) {\r\n                throw new InvalidConfigException(\"Class {$loadModel}::getData() is undefined.\");\r\n            } elseif ($this->cacheTime !== false) {\r\n                $cache = Yii::$app->getCache();\r\n                $cacheKey = $this->getCacheKey();\r\n                if (($data = $cache->get($cacheKey, false)) === false) {\r\n                    $data = $loadModel::getData();\r\n                    $cache->set($cacheKey, $data, $this->cacheTime);\r\n                }\r\n            } else {\r\n                $data = $loadModel::getData();\r\n            }\r\n            $this->setData($data);\r\n\r\n            // 自动保存修改后的数据\r\n            $this->autoSave && register_shutdown_function(function () {\r\n                $this->saveData();\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 获取设置数据\r\n     * @return array\r\n     */\r\n    public function getData()\r\n    {\r\n        return $this->_data;\r\n    }\r\n\r\n    /**\r\n     * 设置设置数据\r\n     * @param $data\r\n     */\r\n    public function setData($data)\r\n    {\r\n        $this->_data = $data;\r\n    }\r\n\r\n    /**\r\n     * 设置指定键值的设置数据\r\n     * @param $name\r\n     * @param $value\r\n     */\r\n    public function set($name, $value)\r\n    {\r\n        $this->_data[$name] = $value;\r\n        $this->_changedDataKeys[] = $name;\r\n    }\r\n\r\n    /**\r\n     * 获取指定键值的设置数据\r\n     * @param $name\r\n     * @param null $defaultValue\r\n     * @return null\r\n     */\r\n    public function get($name, $defaultValue = null)\r\n    {\r\n        return array_key_exists($name, $this->_data) ? $this->_data[$name] : $defaultValue;\r\n    }\r\n\r\n    public function setCacheKey($cacheKey)\r\n    {\r\n        $this->_cacheKey = $cacheKey;\r\n    }\r\n\r\n    public function getCacheKey()\r\n    {\r\n        if ($this->_cacheKey === null) {\r\n            if ($this->loadModel === null) {\r\n                throw new InvalidCallException('The cacheKey property of Config class must be set.');\r\n            }\r\n            $this->setCacheKey('menu_' . md5($this->loadModel));\r\n        }\r\n        return $this->_cacheKey;\r\n    }\r\n\r\n    /**\r\n     * 保存数据(智慧保存修改后的数据)\r\n     * @return mixed\r\n     * @throws \\yii\\base\\InvalidCallException\r\n     */\r\n    public function saveData()\r\n    {\r\n        if ($this->loadModel === null) {\r\n            throw new InvalidCallException(\"The data of class Config can't save. becase loadModel is not set.\");\r\n        }\r\n        $loadModel = $this->loadModel;\r\n        $data = [];\r\n        foreach (array_unique($this->_changedDataKeys) as $name) { // 去重取出修改后的数据\r\n            $data[$name] = $this->get($name);\r\n        }\r\n        if (empty($data)) {\r\n            return true;\r\n        } elseif ($loadModel::saveData($data)) {\r\n            $this->_changedDataKeys; //保存后可以清空了\r\n            Yii::$app->getCache()->delete($this->getCacheKey()); // 更新数据后清除旧缓存\r\n            return true;\r\n        }\r\n        return false;\r\n    }\r\n}\r\n\r\n//class Config extends Object implements \\Countable, \\Iterator, \\ArrayAccess\r\n//{\r\n//    /**\r\n//     * model class 名,如果未指定初始数据, 会根据此值从model类中取数据\r\n//     * @var string\r\n//     */\r\n//    protected $loadModel;\r\n//    /**\r\n//     * 如果指定了loadModel, 缓存的键值,必须注意cache键值, 缓存的键值会经过md5加密, 未指定会使用loadModel代替\r\n//     * @var string\r\n//     */\r\n//    protected $cacheKey;\r\n//    /**\r\n//     * 缓存时间, 如果为0表示永久缓存, false 表示不缓存\r\n//     * @var int|bool\r\n//     */\r\n//    protected $cacheTime = 3600;\r\n//\r\n//    /**\r\n//     * Config 根据数据深度来循环, 该属性会用来标记最终父级分支\r\n//     * @var array\r\n//     */\r\n//    protected $topClass;\r\n//\r\n//    /**\r\n//     * Whether modifications to configuration data are allowed.\r\n//     *\r\n//     * @var bool\r\n//     */\r\n//    protected $allowModifications = true;\r\n//\r\n//    /**\r\n//     * Number of elements in configuration data.\r\n//     *\r\n//     * @var int\r\n//     */\r\n//    protected $count;\r\n//\r\n//    /**\r\n//     * Data within the configuration.\r\n//     *\r\n//     * @var array\r\n//     */\r\n//    protected $data = array();\r\n//\r\n//    /**\r\n//     * Used when unsetting values during iteration to ensure we do not skip\r\n//     * the next element.\r\n//     *\r\n//     * @var bool\r\n//     */\r\n//    protected $skipNextIteration;\r\n//\r\n//    public function __construct(array $data = null, array $properties = [])\r\n//    {\r\n//        foreach ($properties as $name => $value) {\r\n//            $this->$name = $value;\r\n//        }\r\n//\r\n//        if ($data !== null) {\r\n//            $this->setData($data);\r\n//        } else {\r\n//            $this->init();\r\n//        }\r\n//    }\r\n//\r\n//    protected function setData(array $array)\r\n//    {\r\n//        foreach ($array as $key => $value) {\r\n//            if (is_array($value)) {\r\n//                $this->data[$key] = new static($value, [\r\n//                    'allowModifications' => $this->allowModifications,\r\n//                    'topClass' => $this->topClass\r\n//                ]);\r\n//            } else {\r\n//                $this->data[$key] = $value;\r\n//            }\r\n//\r\n//            $this->count++;\r\n//        }\r\n//    }\r\n//\r\n//    public function init()\r\n//    {\r\n//        if ($this->loadModel !== null) {\r\n//            $loadModel = $this->loadModel;\r\n//            if (!method_exists($loadModel, 'getData')) {\r\n//                throw new InvalidConfigException(\"Class {$loadModel}::getData() is undefined.\");\r\n//            } elseif ($this->cacheTime === false) {\r\n//                $data = $loadModel::getData();\r\n//            } else {\r\n//                $cache = Yii::$app->get('cache');\r\n//                $cacheKey = md5($this->cacheKey ? $this->cacheKey : $this->loadModel);\r\n//                if (($data = $cache->get($cacheKey, false)) === false) {\r\n//                    $data = $loadModel::getData();\r\n//                    $cache->set($cacheKey, $data, $this->cacheTime);\r\n//                }\r\n//            }\r\n//            $this->setData($data);\r\n//        }\r\n//    }\r\n//\r\n//    /**\r\n//     * Retrieve a value and return $default if there is no element set.\r\n//     *\r\n//     * @param  string $name\r\n//     * @param  mixed  $default\r\n//     * @return mixed\r\n//     */\r\n//    public function get($name, $default = null)\r\n//    {\r\n//        if (array_key_exists($name, $this->data)) {\r\n//            return $this->data[$name];\r\n//        }\r\n//\r\n//        return $default;\r\n//    }\r\n//\r\n//    /**\r\n//     * Magic function so that $obj->value will work.\r\n//     *\r\n//     * @param  string $name\r\n//     * @return mixed\r\n//     */\r\n//    public function __get($name)\r\n//    {\r\n//        return $this->get($name);\r\n//    }\r\n//\r\n//    /**\r\n//     * Set a value in the config.\r\n//     *\r\n//     * Only allow setting of a property if $allowModifications  was set to true\r\n//     * on construction. Otherwise, throw an exception.\r\n//     *\r\n//     * @param  string $name\r\n//     * @param  mixed  $value\r\n//     * @return void\r\n//     * @throws Exception\\RuntimeException\r\n//     */\r\n//    public function __set($name, $value)\r\n//    {\r\n//        if ($this->allowModifications) {\r\n//\r\n//            if (is_array($value)) {\r\n//                $value = new static($value, true);\r\n//            }\r\n//\r\n//            if (null === $name) {\r\n//                $this->data[] = $value;\r\n//            } else {\r\n//                $this->data[$name] = $value;\r\n//            }\r\n//\r\n//            $this->count++;\r\n//        } else {\r\n//            throw new Exception\\RuntimeException('Config is read only');\r\n//        }\r\n//    }\r\n//\r\n//    /**\r\n//     * Deep clone of this instance to ensure that nested Zend\\Configs are also\r\n//     * cloned.\r\n//     *\r\n//     * @return void\r\n//     */\r\n//    public function __clone()\r\n//    {\r\n//        $array = array();\r\n//\r\n//        foreach ($this->data as $key => $value) {\r\n//            if ($value instanceof self) {\r\n//                $array[$key] = clone $value;\r\n//            } else {\r\n//                $array[$key] = $value;\r\n//            }\r\n//        }\r\n//\r\n//        $this->data = $array;\r\n//    }\r\n//\r\n//    /**\r\n//     * Return an associative array of the stored data.\r\n//     *\r\n//     * @return array\r\n//     */\r\n//    public function toArray()\r\n//    {\r\n//        $array = array();\r\n//        $data  = $this->data;\r\n//\r\n//        /** @var self $value */\r\n//        foreach ($data as $key => $value) {\r\n//            if ($value instanceof self) {\r\n//                $array[$key] = $value->toArray();\r\n//            } else {\r\n//                $array[$key] = $value;\r\n//            }\r\n//        }\r\n//\r\n//        return $array;\r\n//    }\r\n//\r\n//    /**\r\n//     * isset() overloading\r\n//     *\r\n//     * @param  string $name\r\n//     * @return bool\r\n//     */\r\n//    public function __isset($name)\r\n//    {\r\n//        return isset($this->data[$name]);\r\n//    }\r\n//\r\n//    /**\r\n//     * unset() overloading\r\n//     *\r\n//     * @param  string $name\r\n//     * @return void\r\n//     * @throws Exception\\InvalidArgumentException\r\n//     */\r\n//    public function __unset($name)\r\n//    {\r\n//        if (!$this->allowModifications) {\r\n//            throw new Exception\\InvalidArgumentException('Config is read only');\r\n//        } elseif (isset($this->data[$name])) {\r\n//            unset($this->data[$name]);\r\n//            $this->count--;\r\n//            $this->skipNextIteration = true;\r\n//        }\r\n//    }\r\n//\r\n//    /**\r\n//     * count(): defined by Countable interface.\r\n//     *\r\n//     * @see    Countable::count()\r\n//     * @return int\r\n//     */\r\n//    public function count()\r\n//    {\r\n//        return $this->count;\r\n//    }\r\n//\r\n//    /**\r\n//     * current(): defined by Iterator interface.\r\n//     *\r\n//     * @see    Iterator::current()\r\n//     * @return mixed\r\n//     */\r\n//    public function current()\r\n//    {\r\n//        $this->skipNextIteration = false;\r\n//        return current($this->data);\r\n//    }\r\n//\r\n//    /**\r\n//     * key(): defined by Iterator interface.\r\n//     *\r\n//     * @see    Iterator::key()\r\n//     * @return mixed\r\n//     */\r\n//    public function key()\r\n//    {\r\n//        return key($this->data);\r\n//    }\r\n//\r\n//    /**\r\n//     * next(): defined by Iterator interface.\r\n//     *\r\n//     * @see    Iterator::next()\r\n//     * @return void\r\n//     */\r\n//    public function next()\r\n//    {\r\n//        if ($this->skipNextIteration) {\r\n//            $this->skipNextIteration = false;\r\n//            return;\r\n//        }\r\n//\r\n//        next($this->data);\r\n//    }\r\n//\r\n//    /**\r\n//     * rewind(): defined by Iterator interface.\r\n//     *\r\n//     * @see    Iterator::rewind()\r\n//     * @return void\r\n//     */\r\n//    public function rewind()\r\n//    {\r\n//        $this->skipNextIteration = false;\r\n//        reset($this->data);\r\n//    }\r\n//\r\n//    /**\r\n//     * valid(): defined by Iterator interface.\r\n//     *\r\n//     * @see    Iterator::valid()\r\n//     * @return bool\r\n//     */\r\n//    public function valid()\r\n//    {\r\n//        return ($this->key() !== null);\r\n//    }\r\n//\r\n//    /**\r\n//     * offsetExists(): defined by ArrayAccess interface.\r\n//     *\r\n//     * @see    ArrayAccess::offsetExists()\r\n//     * @param  mixed $offset\r\n//     * @return bool\r\n//     */\r\n//    public function offsetExists($offset)\r\n//    {\r\n//        return $this->__isset($offset);\r\n//    }\r\n//\r\n//    /**\r\n//     * offsetGet(): defined by ArrayAccess interface.\r\n//     *\r\n//     * @see    ArrayAccess::offsetGet()\r\n//     * @param  mixed $offset\r\n//     * @return mixed\r\n//     */\r\n//    public function offsetGet($offset)\r\n//    {\r\n//        return $this->__get($offset);\r\n//    }\r\n//\r\n//    /**\r\n//     * offsetSet(): defined by ArrayAccess interface.\r\n//     *\r\n//     * @see    ArrayAccess::offsetSet()\r\n//     * @param  mixed $offset\r\n//     * @param  mixed $value\r\n//     * @return void\r\n//     */\r\n//    public function offsetSet($offset, $value)\r\n//    {\r\n//        $this->__set($offset, $value);\r\n//    }\r\n//\r\n//    /**\r\n//     * offsetUnset(): defined by ArrayAccess interface.\r\n//     *\r\n//     * @see    ArrayAccess::offsetUnset()\r\n//     * @param  mixed $offset\r\n//     * @return void\r\n//     */\r\n//    public function offsetUnset($offset)\r\n//    {\r\n//        $this->__unset($offset);\r\n//    }\r\n//\r\n//    /**\r\n//     * Merge another Config with this one.\r\n//     *\r\n//     * For duplicate keys, the following will be performed:\r\n//     * - Nested Configs will be recursively merged.\r\n//     * - Items in $merge with INTEGER keys will be appended.\r\n//     * - Items in $merge with STRING keys will overwrite current values.\r\n//     *\r\n//     * @param  Config $merge\r\n//     * @return Config\r\n//     */\r\n//    public function merge(Config $merge)\r\n//    {\r\n//        /** @var Config $value */\r\n//        foreach ($merge as $key => $value) {\r\n//            if (array_key_exists($key, $this->data)) {\r\n//                if (is_int($key)) {\r\n//                    $this->data[] = $value;\r\n//                } elseif ($value instanceof self && $this->data[$key] instanceof self) {\r\n//                    $this->data[$key]->merge($value);\r\n//                } else {\r\n//                    if ($value instanceof self) {\r\n//                        $this->data[$key] = new static($value->toArray(), $this->allowModifications);\r\n//                    } else {\r\n//                        $this->data[$key] = $value;\r\n//                    }\r\n//                }\r\n//            } else {\r\n//                if ($value instanceof self) {\r\n//                    $this->data[$key] = new static($value->toArray(), $this->allowModifications);\r\n//                } else {\r\n//                    $this->data[$key] = $value;\r\n//                }\r\n//\r\n//                $this->count++;\r\n//            }\r\n//        }\r\n//\r\n//        return $this;\r\n//    }\r\n//\r\n//    /**\r\n//     * Prevent any more modifications being made to this instance.\r\n//     *\r\n//     * Useful after merge() has been used to merge multiple Config objects\r\n//     * into one object which should then not be modified again.\r\n//     *\r\n//     * @return void\r\n//     */\r\n//    public function setReadOnly()\r\n//    {\r\n//        $this->allowModifications = false;\r\n//\r\n//        /** @var Config $value */\r\n//        foreach ($this->data as $value) {\r\n//            if ($value instanceof self) {\r\n//                $value->setReadOnly();\r\n//            }\r\n//        }\r\n//    }\r\n//\r\n//    /**\r\n//     * Returns whether this Config object is read only or not.\r\n//     *\r\n//     * @return bool\r\n//     */\r\n//    public function isReadOnly()\r\n//    {\r\n//        return !$this->allowModifications;\r\n//    }\r\n//}"
  },
  {
    "path": "common/components/Controller.php",
    "content": "<?php\r\n\r\nnamespace common\\components;\r\n\r\nuse Yii;\r\nuse yii\\helpers\\ArrayHelper;\r\nuse yii\\helpers\\Url;\r\nuse yii\\web\\Response;\r\nuse yiier\\merit\\MeritBehavior;\r\n\r\nclass Controller extends \\yii\\web\\Controller\r\n{\r\n    public function behaviors()\r\n    {\r\n        return ArrayHelper::merge(parent::behaviors(), [\r\n            'returnUrl' => [\r\n                'class' => 'yiier\\returnUrl\\ReturnUrl',\r\n                'uniqueIds' => ['site/qr', 'site/login', 'user/security/auth', 'site/reset-password']\r\n            ],\r\n            MeritBehavior::className(),\r\n        ]);\r\n    }\r\n\r\n    public function beforeAction($action)\r\n    {\r\n        if (parent::beforeAction($action)) {\r\n            return true;\r\n        } else {\r\n            return false;\r\n        }\r\n    }\r\n\r\n    public function afterAction($action, $result)\r\n    {\r\n        if (!Yii::$app->user->isGuest) {\r\n            $actionName = \"frontend@{$this->module->id}_{$this->id}_{$action->id}\";\r\n        }\r\n        return parent::afterAction($action, $result);\r\n    }\r\n\r\n    /**\r\n     * 显示flash信息\r\n     * @param $message string 信息显示内容\r\n     * @param string $type 信息显示类型, ['info', 'success', 'error', 'warning']\r\n     * @param null $url 跳转地址\r\n     * @throws \\yii\\base\\ExitException\r\n     */\r\n    public function flash($message, $type = 'info', $url = null)\r\n    {\r\n        Yii::$app->getSession()->setFlash($type, $message);\r\n        if ($url !== null) {\r\n            Yii::$app->end(0, $this->redirect($url));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @param $message string 信息显示内容\r\n     * @param string $type 信息显示类型, ['info', 'success', 'error', 'warning']\r\n     * @param null $redirect 跳转地址\r\n     * @param null $resultType 信息显示格式\r\n     * @return array|string\r\n     */\r\n    public function message($message, $type = 'info', $redirect = null, $resultType = null)\r\n    {\r\n        $resultType === null && $resultType = Yii::$app->getRequest()->getIsAjax() ? 'json' : 'html';\r\n        is_array($redirect) && $redirect = Url::to($redirect);\r\n        $data = [\r\n            'type' => $type,\r\n            'message' => $message,\r\n            'redirect' => $redirect\r\n        ];\r\n\r\n        if ($resultType === 'json') {\r\n            Yii::$app->getResponse()->format = Response::FORMAT_JSON;\r\n            return $data;\r\n        } elseif ($resultType === 'html') {\r\n            return $this->render('/common/message', $data);\r\n        }\r\n    }\r\n\r\n    // public $ajaxLayout = '/ajaxMain';\r\n    // public function findLayoutFile($view)\r\n    // {\r\n    //     if (($this->layout === null) && ($this->ajaxLayout !== false) && Yii::$app->getRequest()->getIsAjax()) {\r\n    //         $this->layout = $this->ajaxLayout;\r\n    //     }\r\n    //     return parent::findLayoutFile($view);\r\n    // }\r\n}"
  },
  {
    "path": "common/components/DbAuthManager.php",
    "content": "<?php\r\nnamespace common\\components;\r\n\r\nuse yii\\db\\Query;\r\nuse yii\\rbac\\Item;\r\nuse yii\\rbac\\DbManager;\r\n\r\nclass DbAuthManager extends DbManager\r\n{\r\n    protected function getChildrenListOfType($type)\r\n    {\r\n        $query = (new Query)->from($this->itemChildTable)\r\n            ->join('INNER JOIN', $this->itemTable, implode(' AND ', [\r\n                $this->itemTable . '.name=' . $this->itemChildTable . '.child',\r\n                $this->itemTable . '.type = ' . $type\r\n            ]));\r\n        $parents = [];\r\n        foreach ($query->all($this->db) as $row) {\r\n            $parents[$row['parent']][] = $row['child'];\r\n        }\r\n        return $parents;\r\n    }\r\n\r\n    /**\r\n     * @params bool $recursive 是否递归显示子角色权限\r\n     * @inheritdoc\r\n     */\r\n    public function getPermissionsByRole($roleName, $recursive = true)\r\n    {\r\n        $childrenList = $recursive ? $this->getChildrenList() : $this->getChildrenListOfType(Item::TYPE_PERMISSION);\r\n        $result = [];\r\n        $this->getChildrenRecursive($roleName, $childrenList, $result);\r\n        if (empty($result)) {\r\n            return [];\r\n        }\r\n        $query = (new Query)->from($this->itemTable)->where([\r\n            'type' => Item::TYPE_PERMISSION,\r\n            'name' => array_keys($result),\r\n        ]);\r\n        $permissions = [];\r\n        foreach ($query->all($this->db) as $row) {\r\n            $permissions[$row['name']] = $this->populateItem($row);\r\n        }\r\n        return $permissions;\r\n    }\r\n}\r\n"
  },
  {
    "path": "common/components/FileTarget.php",
    "content": "<?php\n\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 2015/12/22 18:13\n * description:\n */\nnamespace common\\components;\n\nuse Yii;\nuse yii\\helpers\\FileHelper;\n\nclass FileTarget extends \\yii\\log\\FileTarget\n{\n    /**\n     * @var bool 是否启用日志前缀 (@app/runtime/logs/error/20151223_app.log)\n     */\n    public $enableDatePrefix = false;\n\n    /**\n     * @var bool 启用日志等级目录\n     */\n    public $enableCategoryDir = false;\n\n    private $_logFilePath = '';\n\n    public function init()\n    {\n        if ($this->logFile === null) {\n            $this->logFile = Yii::$app->getRuntimePath() . '/logs/app.log';\n        } else {\n            $this->logFile = Yii::getAlias($this->logFile);\n        }\n        $this->_logFilePath = dirname($this->logFile);\n\n        // 启用日志前缀\n        if ($this->enableDatePrefix) {\n            $filename = basename($this->logFile);\n            $this->logFile = $this->_logFilePath . '/' . date('Ymd') . '_' . $filename;\n        }\n\n        if (!is_dir($this->_logFilePath)) {\n            FileHelper::createDirectory($this->_logFilePath, $this->dirMode, true);\n        }\n\n        if ($this->maxLogFiles < 1) {\n            $this->maxLogFiles = 1;\n        }\n        if ($this->maxFileSize < 1) {\n            $this->maxFileSize = 1;\n        }\n\n    }\n}"
  },
  {
    "path": "common/components/GlobalFunctions.php",
    "content": "<?php\n\nuse yii\\web\\Response;\n\nif (!function_exists('env')) {\n\n    function env($envName, $default = false)\n    {\n        $envName = getenv($envName);\n\n        return $envName === false ? $default : $envName;\n    }\n}\n\n\nif (!function_exists('app')) {\n    /**\n     * App或App的定义组件\n     *\n     * @param null $component Yii组件名称\n     * @param bool $throwException 获取未定义组件是否报错\n     * @return null|object|\\yii\\console\\Application|\\yii\\web\\Application\n     * @throws \\yii\\base\\InvalidConfigException\n     */\n    function app($component = null, $throwException = true)\n    {\n        if ($component === null) {\n            return Yii::$app;\n        }\n        return Yii::$app->get($component, $throwException);\n    }\n}\nif (!function_exists('t')) {\n    /**\n     * i18n 国际化\n     * @param $category\n     * @param $message\n     * @param array $params\n     * @param null $language\n     * @return string\n     */\n    function t($category, $message, $params = [], $language = null)\n    {\n        return Yii::t($category, $message, $params, $language);\n    }\n}\n\nif (!function_exists('user')) {\n    /**\n     * User组件或者(设置|返回)identity属性\n     *\n     * @param null|string|array $attribute idenity属性\n     * @return \\yii\\web\\User|string|array\n     */\n    function user($attribute = null)\n    {\n        if ($attribute === null) {\n            return Yii::$app->getUser();\n        }\n        if (is_array($attribute)) {\n            return Yii::$app->getUser()->getIdentity()->setAttributes($attribute);\n        }\n        return Yii::$app->getUser()->getIdentity()->{$attribute};\n    }\n}\nif (!function_exists('request')) {\n    /**\n     * Request组件或者通过Request组件获取GET值\n     *\n     * @param string $key\n     * @param mixed $default\n     * @return \\yii\\web\\Request|string|array\n     */\n    function request($key = null, $default = null)\n    {\n        if ($key === null) {\n            return Yii::$app->getRequest();\n        }\n        return Yii::$app->getRequest()->getQueryParam($key, $default);\n    }\n}\nif (!function_exists('response')) {\n    /**\n     * Response组件或者通过Response组织内容\n     *\n     * @param string $content 响应内容\n     * @param string $format 响应格式\n     * @return \\yii\\web\\Response\n     */\n    function response($content = '', $format = Response::FORMAT_HTML, $status = null)\n    {\n        $response = Yii::$app->getResponse();\n        if (func_num_args() !== 0) {\n            $response->format = $format;\n            if ($status !== null) {\n                $response->setStatusCode($status);\n            }\n            if ($format === Response::FORMAT_HTML) {\n                $response->content = $content;\n            } else {\n                $response->data = $content;\n            }\n        }\n        return $response;\n    }\n}\n\nif (!function_exists('params')) {\n    /**\n     * params 组件或者通过 params 组件获取GET值\n     * @param $key\n     * @return mixed|\\yii\\web\\Session\n     */\n    function params($key)\n    {\n        return Yii::$app->params[$key];\n    }\n}\n\n/**\n * @param $message\n * @param bool|true $debug\n */\nfunction pr($message, $debug = true)\n{\n    echo '<pre>';\n    print_r($message);\n    echo '</pre>';\n    if ($debug) {\n        die;\n    }\n}"
  },
  {
    "path": "common/components/Mailer.php",
    "content": "<?php\n\nnamespace common\\components;\n\nuse yii\\base\\Component;\n\nclass Mailer extends Component\n{\n    /** @var string */\n    public $viewPath = '@dektrium/user/views/mail';\n    /** @var string|array */\n    public $sender = 'no-reply@example.com';\n    /** @var string */\n    public $welcomeSubject;\n    /** @var string */\n    public $confirmationSubject;\n    /** @var string */\n    public $reconfirmationSubject;\n    /** @var string */\n    public $recoverySubject;\n\n    public function init()\n    {\n        parent::init();\n        \\Yii::$app->set('mailer', [\n            'class' => 'yii\\swiftmailer\\Mailer',\n            'viewPath' => '@common/mail',\n            'transport' => [\n                'class' => 'Swift_SmtpTransport',\n                'host' => \\Yii::$app->setting->get('smtpHost'),\n                'username' => \\Yii::$app->setting->get('smtpUser'),\n                'password' => \\Yii::$app->setting->get('smtpPassword'),\n                'port' => \\Yii::$app->setting->get('smtpPort'),\n                // 'mail' => \\Yii::$app->setting->get('smtpMail'), // 显示地址\n                'encryption' => 'tls',\n            ],\n        ]);\n    }\n\n    /**\n     * Sends an email to a user with credentials and confirmation link.\n     *\n     * @param  User $user\n     * @param  Token $token\n     * @return bool\n     */\n    public function sendWelcomeMessage(User $user, Token $token = null)\n    {\n        return $this->sendMessage($user->email,\n            $this->welcomeSubject,\n            'welcome',\n            ['user' => $user, 'token' => $token]\n        );\n    }\n\n    /**\n     * @param  string $to\n     * @param  string $subject\n     * @param  string $view\n     * @param  array $params\n     * @return bool\n     */\n    protected function sendMessage($to, $subject, $view, $params = [])\n    {\n        $mailer = \\Yii::$app->mailer;\n        $mailer->viewPath = $this->viewPath;\n        $mailer->getView()->theme = \\Yii::$app->view->theme;\n\n        return $mailer->compose(['html' => $view, 'text' => 'text/' . $view], $params)\n            ->setTo($to)\n            ->setFrom($this->sender)\n            ->setSubject($subject)\n            ->send();\n    }\n\n    /**\n     * Sends an email to a user with confirmation link.\n     *\n     * @param  User $user\n     * @param  Token $token\n     * @return bool\n     */\n    public function sendConfirmationMessage(User $user, Token $token)\n    {\n        return $this->sendMessage($user->email,\n            $this->confirmationSubject,\n            'confirmation',\n            ['user' => $user, 'token' => $token]\n        );\n    }\n\n    /**\n     * Sends an email to a user with reconfirmation link.\n     *\n     * @param  User $user\n     * @param  Token $token\n     * @return bool\n     */\n    public function sendReconfirmationMessage(User $user, Token $token)\n    {\n        if ($token->type == Token::TYPE_CONFIRM_NEW_EMAIL) {\n            $email = $user->unconfirmed_email;\n        } else {\n            $email = $user->email;\n        }\n        return $this->sendMessage($email,\n            $this->reconfirmationSubject,\n            'reconfirmation',\n            ['user' => $user, 'token' => $token]\n        );\n    }\n\n    /**\n     * Sends an email to a user with recovery link.\n     *\n     * @param  User $user\n     * @param  Token $token\n     * @return bool\n     */\n    public function sendRecoveryMessage(User $user, Token $token)\n    {\n        return $this->sendMessage($user->email,\n            $this->recoverySubject,\n            'recovery',\n            ['user' => $user, 'token' => $token]\n        );\n    }\n}"
  },
  {
    "path": "common/components/db/ActiveRecord.php",
    "content": "<?php\r\nnamespace common\\components\\db;\r\n\r\nclass ActiveRecord extends \\yii\\db\\ActiveRecord\r\n{\r\n\t/**\r\n     * 自动更新created_at和updated_at时间\r\n     * @return array\r\n     */\r\n    public function behaviors()\r\n    {\r\n        return [\r\n            'timestamp' => [\r\n                'class' => 'yii\\behaviors\\TimestampBehavior',\r\n            ],\r\n        ];\r\n    }\r\n}"
  },
  {
    "path": "common/components/db/Command.php",
    "content": "<?php\r\nnamespace common\\components\\db;\r\n\r\nclass Command extends \\yii\\db\\Command\r\n{\r\n\r\n    /**\r\n     * @param $replace 是否替换数据,如果为真, 则创建REPLACE INTO sql语句 (Only Mysql)\r\n     * @see \\yii\\db\\Command::batchInsert();\r\n     */\r\n    public function batchReplace($table, $columns, $rows)\r\n    {\r\n        $sql = $this->db->getQueryBuilder()->batchInsert($table, $columns, $rows);\r\n        return $this->setSql('REPLACE' . substr($sql, strpos($sql, ' ')));\r\n    }\r\n\r\n}\r\n\r\n?>"
  },
  {
    "path": "common/components/db/Connection.php",
    "content": "<?php\r\nnamespace common\\components\\db;\r\n\r\nclass Connection extends \\yii\\db\\Connection\r\n{\r\n    /**\r\n     * @see \\yii\\db\\Connection::createCommand\r\n     */\r\n    public function createCommand($sql = null, $params = [])\r\n    {\r\n        $this->open();\r\n        $command = new Command([ // 使用了继承了之后的Command类..\r\n            'db' => $this,\r\n            'sql' => $sql,\r\n        ]);\r\n\r\n        return $command->bindValues($params);\r\n    }\r\n}"
  },
  {
    "path": "common/components/db/Migration.php",
    "content": "<?php\r\nnamespace common\\components\\db;\r\n\r\nclass Migration extends \\yii\\db\\Migration\r\n{\r\n    /**\r\n     * 创建表选项\r\n     * @var string\r\n     */\r\n    public $tableOptions = null;\r\n\r\n    /**\r\n     * 是否事务性存储表, 则创建为事务性表. 默认不使用\r\n     * @var bool\r\n     */\r\n    public $useTransaction = false;\r\n\r\n\r\n    public function init()\r\n    {\r\n        parent::init();\r\n\r\n        if ($this->db->driverName === 'mysql') { //Mysql 表选项\r\n            $engine = $this->useTransaction ? 'InnoDB' : 'MyISAM';\r\n            $this->tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=' . $engine;\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "common/config/.gitignore",
    "content": "main-local.php\nparams-local.php\ndb.php\n"
  },
  {
    "path": "common/config/bootstrap.php",
    "content": "<?php\nYii::setAlias('common', dirname(__DIR__));\nYii::setAlias('root', dirname(dirname(__DIR__)));\nYii::setAlias('frontend', dirname(dirname(__DIR__)) . '/frontend');\nYii::setAlias('backend', dirname(dirname(__DIR__)) . '/backend');\nYii::setAlias('console', dirname(dirname(__DIR__)) . '/console');\n"
  },
  {
    "path": "common/config/main.php",
    "content": "<?php\nreturn [\n//    'aliases' => [\n//        '@bower' => '@vendor/bower-asset',\n//        '@npm' => '@vendor/npm-asset',\n//    ],\n    'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',\n    'timeZone' => 'Asia/Shanghai', //time zone affect the formatter datetime format\n    'language' => 'zh-CN',\n    'modules' => [\n    ],\n    'components' => [\n        'formatter' => [ //for the showing of date datetime\n            'dateFormat' => 'yyyy-MM-dd',\n            'locale' => 'zh-CN',\n            'datetimeFormat' => 'yyyy-MM-dd HH:mm:ss',\n            'decimalSeparator' => ',',\n            'thousandSeparator' => ' ',\n            'currencyCode' => 'CNY',\n        ],\n        'setting' => [\n            'class' => 'funson86\\setting\\Setting',\n        ],\n        'qr' => [\n            'class' => '\\Da\\QrCode\\Component\\QrCodeComponent',\n//            'label' => '2amigos consulting group llc',\n            'size' => 500 // big and nice :D\n            // ... you can configure more properties of the component here\n        ],\n        'mailer' => [\n            'class' => 'yii\\swiftmailer\\Mailer',\n            'viewPath' => '@common/mail',\n        ],\n        'cache' => [\n            'class' => 'yii\\caching\\FileCache',\n            //'class' => 'yii\\caching\\ApcCache',\n            'cachePath' => '@backend/runtime/cache',\n        ],\n        'slack' => [\n            'httpclient' => ['class' => 'yii\\httpclient\\Client'],\n            'class' => 'understeam\\slack\\Client',\n            'url' => '',\n        ],\n//        'assetManager' => [\n//            'linkAssets' => true,\n//        ],\n        'log' => [\n            'traceLevel' => YII_DEBUG ? 3 : 0,\n            'targets' => [\n                [\n                    'class' => 'understeam\\slack\\LogTarget',\n                    'enabled' => false, // 是否开启错误信息发送 Slack 服务，默认否\n                    'levels' => ['error'],\n                    'categories' => [\n                        'yii\\db\\*',\n                        'yii\\web\\HttpException:*',\n                    ],\n                    'except' => [\n                        'yii\\web\\HttpException:404', // 除了404错误\n                    ],\n                    'exportInterval' => 1, // Send logs on every message\n                    'logVars' => [],\n                ],\n                [\n                    'class' => 'yii\\log\\FileTarget',\n                    'levels' => ['error', 'warning', 'info', 'trace'],\n                ],\n                /**\n                 * 错误级别日志：当某些需要立马解决的致命问题发生的时候，调用此方法记录相关信息。\n                 * 使用方法：Yii::error()\n                 */\n                [\n                    'class' => 'common\\components\\FileTarget',\n                    // 日志等级\n                    'levels' => ['error'],\n                    // 被收集记录的额外数据\n                    'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'],\n                    // 指定日志保存的文件名\n                    'logFile' => '@app/runtime/logs/error/app.log',\n                    // 是否开启日志 (@app/runtime/logs/error/20151223_app.log)\n                    'enableDatePrefix' => true,\n                ],\n                /**\n                 * 警告级别日志：当某些期望之外的事情发生的时候，使用该方法。\n                 * 使用方法：Yii::warning()\n                 */\n                [\n                    'class' => 'common\\components\\FileTarget',\n                    // 日志等级\n                    'levels' => ['warning'],\n                    // 被收集记录的额外数据\n                    'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'],\n                    // 指定日志保存的文件名\n                    'logFile' => '@app/runtime/logs/warning/app.log',\n                    // 是否开启日志 (@app/runtime/logs/warning/20151223_app.log)\n                    'enableDatePrefix' => true,\n                ],\n                /**\n                 * info 级别日志：在某些位置记录一些比较有用的信息的时候使用。\n                 * 使用方法：Yii::info()\n                 */\n                [\n                    'class' => 'common\\components\\FileTarget',\n                    'enabled' => YII_DEBUG, // debug 模式才开启\n                    // 日志等级\n                    'levels' => ['info'],\n                    // 被收集记录的额外数据\n                    'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'],\n                    // 指定日志保存的文件名\n                    'logFile' => '@app/runtime/logs/info/app.log',\n                    // 是否开启日志 (@app/runtime/logs/info/20151223_app.log)\n                    'enableDatePrefix' => true,\n                ],\n                /**\n                 * trace 级别日志：记录关于某段代码运行的相关消息。主要是用于开发环境。\n                 * 使用方法：Yii::trace()\n                 */\n                [\n                    'class' => 'common\\components\\FileTarget',\n                    'enabled' => YII_DEBUG, // debug 模式才开启\n                    // 日志等级\n                    'levels' => ['trace'],\n                    // 被收集记录的额外数据\n                    'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'],\n                    // 指定日志保存的文件名\n                    'logFile' => '@app/runtime/logs/trace/app.log',\n                    // 是否开启日志 (@app/runtime/logs/trace/20151223_app.log)\n                    'enableDatePrefix' => true,\n                ],\n            ],\n        ],\n        'session' => [\n            'class' => 'yii\\web\\DbSession',\n        ],\n        'db' => require(__DIR__ . '/db.php'),\n        'i18n' => [\n            'translations' => [\n                'frontend*' => [\n                    'class' => 'yii\\i18n\\PhpMessageSource',\n                    'basePath' => '@common/messages',\n                ],\n                'backend*' => [\n                    'class' => 'yii\\i18n\\PhpMessageSource',\n                    'basePath' => '@common/messages',\n                ],\n                'common*' => [\n                    'class' => 'yii\\i18n\\PhpMessageSource',\n                    'basePath' => '@common/messages',\n                ],\n            ],\n        ],\n    ],\n];\n"
  },
  {
    "path": "common/config/params.php",
    "content": "<?php\nreturn [\n    'adminEmail' => 'caizhenghai@gmail.com',\n    'backupEmail' => 'caizhenghai@qq.com',\n    'supportEmail' => 'forecho@foxmail.com',\n    'user.passwordResetTokenExpire' => 3600,\n//    'avatarPath' => Yii::$app->basePath . '/uploads/avatars/',\n//    'avatarUrl' => Yii::$app->urlManager->baseUrl . '/uploads/avatars/',\n    'avatarPath' => '/web/uploads/avatars/',\n    'avatarUrl' => '/uploads/avatars/',\n    'avatarCachePath' => '/web/uploads/avatars/cache/',\n    'avatarCacheUrl' => '/uploads/avatars/cache/',\n    'icon-framework' => 'fa',  // Font Awesome Icon framework\n    'qrCodePath' => '/web/uploads/qr-code/',\n    'qrCodeUrl' => '/uploads/qr-code/',\n    'newUserPostLimit' => 0, // 防止 spam，可限制新注册用户多少秒之后才能发帖，默认 0 代表不限制，单位是秒\n    'smToken' => '', // https://sm.ms/home/apitoken\n    'createPostNeedVerify' => false, // 发帖是否需要审核\n];\n"
  },
  {
    "path": "common/grid/EnumColumn.php",
    "content": "<?php\nnamespace common\\grid;\n\nuse yii\\grid\\DataColumn;\nuse yii\\helpers\\ArrayHelper;\n\n/**\n * Class EnumColumn\n * [\n *      'class' => 'common\\grid\\EnumColumn',\n *      'attribute' => 'role',\n *      'enum' => User::getRoles()\n * ]\n * @package common\\components\\grid\n */\nclass EnumColumn extends DataColumn\n{\n    /**\n     * @var array List of value => name pairs\n     */\n    public $enum = [];\n    /**\n     * @var bool\n     */\n    public $loadFilterDefaultValues = true;\n\n    /**\n     * @inheritdoc\n     */\n    public function init()\n    {\n        if ($this->loadFilterDefaultValues && $this->filter === null) {\n            $this->filter = $this->enum;\n        }\n    }\n\n    /**\n     * @param mixed $model\n     * @param mixed $key\n     * @param int $index\n     * @return mixed\n     */\n    public function getDataCellValue($model, $key, $index)\n    {\n        $value = parent::getDataCellValue($model, $key, $index);\n        return ArrayHelper::getValue($this->enum, $value, $value);\n    }\n}\n"
  },
  {
    "path": "common/helpers/Arr.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 16/3/19 上午9:57\n * description:\n */\n\nnamespace common\\helpers;\n\n\nuse yii\\helpers\\ArrayHelper;\n\nclass Arr extends ArrayHelper\n{\n    /**\n     * 随机筛选$num个数组\n     * @param array $arr\n     * @param int $num\n     * @return array|false\n     */\n    public static function arrayRandomAssoc(Array $arr, $num = 1)\n    {\n        if (!$arr) {\n            return false;\n        }\n        $keys = array_keys($arr);\n        shuffle($keys);\n\n        $r = [];\n        for ($i = 0; $i < $num; $i++) {\n            $r[$keys[$i]] = $arr[$keys[$i]];\n        }\n        return $r;\n    }\n}"
  },
  {
    "path": "common/helpers/Avatar.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/5/17 下午4:14\n * description:\n */\n\nnamespace common\\helpers;\n\nclass Avatar\n{\n    public $email;\n    public $size;\n\n    public function __construct($email, $size = 50)\n    {\n        $this->email = $email;\n        $this->size = $size;\n    }\n\n    public function getAvater()\n    {\n        // 说明： Gravatar 随机头像太丑了 所以使用 Identicon 随机头像\n        // TODO 保存头像图片 加缓存\n        // return $this->getGravatar();\n        $identicon = new \\Identicon\\Identicon();\n        return $identicon->getImageDataUri($this->email, $this->size);\n    }\n\n    /**\n     * 根据 email 获取 gravatar 头像的地址\n     * @return string\n     */\n    private function getGravatar()\n    {\n        $hash = md5(strtolower(trim($this->email)));\n        return sprintf('http://gravatar.com/avatar/%s?s=%d&d=%s', $hash, $this->size, 'identicon');\n    }\n\n    /**\n     * 验证email是否有对应的 Gravatar 头像（效率太低）\n     * @return bool\n     */\n    private function validateGravatar()\n    {\n        $hash = md5(strtolower(trim($this->email)));\n        $uri = 'http://gravatar.com/avatar/' . $hash . '?d=404';\n        $headers = @get_headers($uri);\n        if (!preg_match(\"|200|\", $headers[0])) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n}"
  },
  {
    "path": "common/helpers/Formatter.php",
    "content": "<?php\r\n/**\r\n * author     : forecho <caizhenghai@gmail.com>\r\n * createTime : 2015/8/4 14:19\r\n * description:\r\n */\r\n\r\nnamespace common\\helpers;\r\n\r\nclass Formatter\r\n{\r\n    const DATE_FORMAT = 'php:Y-m-d';\r\n    const DATETIME_FORMAT = 'php:Y-m-d H:i:s';\r\n    const TIME_FORMAT = 'php:H:i:s';\r\n\r\n    public static function convert($dateStr, $type = 'date', $format = null)\r\n    {\r\n        if ($type === 'datetime') {\r\n            $fmt = ($format == null) ? self::DATETIME_FORMAT : $format;\r\n        } elseif ($type === 'time') {\r\n            $fmt = ($format == null) ? self::TIME_FORMAT : $format;\r\n        } else {\r\n            $fmt = ($format == null) ? self::DATE_FORMAT : $format;\r\n        }\r\n        return \\Yii::$app->formatter->asDate($dateStr, $fmt);\r\n    }\r\n\r\n    /**\r\n     * 相对时间\r\n     * @param $dateStr\r\n     * @return string\r\n     */\r\n    public static function relative($dateStr)\r\n    {\r\n        return \\Yii::$app->formatter->asRelativeTime($dateStr);\r\n    }\r\n}"
  },
  {
    "path": "common/helpers/UploadHelper.php",
    "content": "<?php\r\n/**\r\n * Created by PhpStorm.\r\n * User: user\r\n * Date: 2017/1/18\r\n * Time: 17:56\r\n */\r\n\r\nnamespace common\\helpers;\r\n\r\n\r\nclass UploadHelper\r\n{\r\n    public static function getCurlValue($filename, $contentType, $postname)\r\n    {\r\n        // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax\r\n        // See: https://wiki.php.net/rfc/curl-file-upload\r\n        if (function_exists('curl_file_create')) {\r\n            return curl_file_create($filename, $contentType, $postname);\r\n        }\r\n\r\n        // Use the old style if using an older version of PHP\r\n        $value = \"@{$filename};filename=\" . $postname;\r\n        if ($contentType) {\r\n            $value .= ';type=' . $contentType;\r\n        }\r\n\r\n        return $value;\r\n    }\r\n\r\n}"
  },
  {
    "path": "common/mail/backup.php",
    "content": "\n\n数据库备份成功！！！！\n\n"
  },
  {
    "path": "common/mail/layouts/html.php",
    "content": "<?php\nuse yii\\helpers\\Html;\n\n/* @var $this \\yii\\web\\View view component instance */\n/* @var $message \\yii\\mail\\MessageInterface the message being composed */\n/* @var $content string main view render result */\n?>\n<?php $this->beginPage() ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=<?= Yii::$app->charset ?>\" />\n    <title><?= Html::encode($this->title) ?></title>\n    <?php $this->head() ?>\n</head>\n<body>\n    <?php $this->beginBody() ?>\n    <?= $content ?>\n    <?php $this->endBody() ?>\n</body>\n</html>\n<?php $this->endPage() ?>\n"
  },
  {
    "path": "common/mail/passwordResetToken.php",
    "content": "<?php\nuse yii\\helpers\\Html;\n\n/* @var $this yii\\web\\View */\n/* @var $user common\\models\\User */\n\n$resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]);\n?>\n\nHello <?= Html::encode($user->username) ?>,\n\nFollow the link below to reset your password:\n\n<?= Html::a(Html::encode($resetLink), $resetLink) ?>\n"
  },
  {
    "path": "common/messages/pt-BR/backend.php",
    "content": "<?php\nreturn [\n    'DELETED' => 'EXCLUÍDO',\n    'ACTIVE' => 'ATIVO',\n    'EXCELLENT' => 'EXCELENTE',\n    'TOP' => 'TOP',\n    'Username' => 'Usuário',\n    'Password' => 'Senha',\n    'Remember Me' => 'Lembrar-me',\n    'Sign in' => 'Acessar',\n    'Article View' => 'Ver artigo',\n    'Page View' => 'Ver Página',\n    '\"{attribute}\" must be a valid JSON' => '\"{attribute}\" precisa ser JSON válido',\n    'Active' => 'Ativo',\n    'Article ID' => 'ID artigo',\n    'Author' => 'Autor',\n    'Base URL' => 'URL Base',\n    'Base Url' => 'Url Base',\n    'Body' => 'Corpo',\n    'Caption' => 'Legenda',\n    'Carousel ID' => 'Carrossel ID',\n    'Category' => 'Categoria',\n    'Comment' => 'Comentario',\n    'Component' => 'Componente',\n    'Config' => 'Configuracão',\n    'Created At' => 'Criado Em',\n    'Created at' => 'Criado em',\n    'Deleted' => 'Excluído',\n    'Down to maintenance.' => 'Desativado para manutenção',\n    'E-mail' => 'E-mail',\n    'File Type' => 'Tipo de arquivo',\n    'Firstname' => 'Nome',\n    'Gender' => 'Genero',\n    'ID' => 'ID',\n    'Image' => 'Imagen',\n    'Key' => 'Chave',\n    'Last login' => 'Ultimo Login',\n    'Lastname' => 'Ultimo Nome',\n    'Locale' => 'Localidade',\n    'Middlename' => 'Nome do meio',\n    'Name' => 'Nome',\n    'Order' => 'Ordem',\n    'Parent Category' => 'Categoria Pai',\n    'Path' => 'Caminho',\n    'Picture' => 'Imagen',\n    'Published' => 'Publicado',\n    'Published At' => 'Publicado em',\n    'Size' => 'Tamanho',\n    'Slug' => 'Slug',\n    'Status' => 'Status',\n    'Thumbnail' => 'Miniatura',\n    'Title' => 'Título',\n    'Type' => 'Tipo',\n    'Updated At' => 'Atualizado Em',\n    'Updated at' => 'Atualizado em',\n    'Updater' => 'Atualizado por',\n    'Upload Ip' => 'IP',\n    'Url' => 'Url',\n    'User ID' => 'ID do Usuario',\n    'Value' => 'Valor',\n];"
  },
  {
    "path": "common/messages/pt-BR/common.php",
    "content": "<?php\nreturn [\n    'DELETED' => 'EXCLUIDO',\n    'ACTIVE' => 'ATIVO',\n    'EXCELLENT' => 'EXCELENTE',\n    'TOP' => 'TOP',\n    'Username' => 'Usuário',\n    'Password' => 'Senha',\n    'Remember Me' => 'Lembrar-me',\n    'Incorrect username or password.' => 'Usuário ou senha inválido',\n    'You don\\'t have permission to login.' => 'Você não tem permissão pra autenticar',\n    'User ID' => 'ID do usuário',\n    'Type' => 'Tipo',\n    'Merit' => 'Mérito',\n    'Created At' => 'Criado em',\n    'Updated At' => 'Alterado em',\n    'Merit Template ID' => 'Cod Template Merit',\n    'Description' => 'Descrição',\n    'Action Type' => 'Tipo de Ação',\n    'Increment' => 'Incremento',\n];"
  },
  {
    "path": "common/messages/pt-BR/frontend.php",
    "content": "<?php\nreturn [\n    'created_at {datetime}' => 'criado em {datetime}',\n    'reply_at {datetime}' => 'respondido em {datetime}',\n    'last_by' => 'Por',\n];"
  },
  {
    "path": "common/messages/zh-CN/backend.php",
    "content": "<?php\nreturn [\n    'DELETED' => '已删除',\n    'ACTIVE' => '正常',\n    'EXCELLENT' => '推荐',\n    'TOP' => '置顶',\n    'Username' => '用户名',\n    'Password' => '密码',\n    'Remember Me' => '记住我',\n    'Sign in' => '登录',\n    'Article View' => 'Vista de Artículo',\n    'Page View' => 'Vista de Página',\n    '\"{attribute}\" must be a valid JSON' => '\"{attribute}\" debe de ser JSON válido',\n    'Active' => 'Activo',\n    'Article ID' => 'ID Artículo',\n    'Author' => 'Autor',\n    'Base URL' => 'URL Base',\n    'Base Url' => 'Url Base',\n    'Body' => 'Cuerpo',\n    'Caption' => 'Leyenda',\n    'Carousel ID' => 'Carrusel ID',\n    'Category' => 'Categoría',\n    'Comment' => 'Comentario',\n    'Component' => 'Componente',\n    'Config' => 'Configuración',\n    'Created At' => 'Creado el',\n    'Created at' => 'Creado el',\n    'Deleted' => 'Borrado',\n    'Down to maintenance.' => 'Apagado por mantenimiento.',\n    'E-mail' => 'E-mail',\n    'File Type' => 'Tipo fichero',\n    'Firstname' => 'Nombre',\n    'Gender' => 'Género',\n    'ID' => 'ID',\n    'Image' => 'Imagen',\n    'Key' => 'Clave',\n    'Last login' => 'ültimo Login',\n    'Lastname' => 'Apellido',\n    'Locale' => 'Pais',\n    'Middlename' => 'Segundo Nombre',\n    'Name' => 'Nombre',\n    'Order' => 'Orden',\n    'Parent Category' => 'Categoría Padre',\n    'Path' => 'Ruta',\n    'Picture' => 'Imagen',\n    'Published' => 'Publicado',\n    'Published At' => 'Publicado el',\n    'Size' => 'Tamaño',\n    'Slug' => 'Slug',\n    'Status' => 'Estado',\n    'Thumbnail' => 'Miniatura',\n    'Title' => 'Título',\n    'Type' => 'Tipo',\n    'Updated At' => 'Actualizado el',\n    'Updated at' => 'Actualizado el',\n    'Updater' => 'Actualizado por',\n    'Upload Ip' => 'IP',\n    'Url' => 'Url',\n    'User ID' => 'Usuario ID',\n    'Value' => 'Valor',\n];"
  },
  {
    "path": "common/messages/zh-CN/common.php",
    "content": "<?php\n\nreturn [\n    'DELETED' => '已删除',\n    'ACTIVE' => '正常',\n    'EXCELLENT' => '推荐',\n    'TOP' => '置顶',\n\n    'Username' => '用户名/邮箱',\n    'Password' => '密码',\n    'Remember Me' => '记住我',\n    'Incorrect username or password.' => '用户名密码验证失败。',\n    'You don\\'t have permission to login.' => '你没有登录权限。',\n    'User ID' => '用户 ID',\n    'Type' => '分类',\n    'Merit' => '总值',\n    'Created At' => '创建时间',\n    'Updated At' => '更新时间',\n    'Merit Template ID' => '模板ID',\n    'Description' => '描述',\n    'Action Type' => '操作类型  0减去 1新增',\n    'Increment' => '变化值',\n\n\n];"
  },
  {
    "path": "common/messages/zh-CN/frontend.php",
    "content": "<?php\n\nreturn [\n    'created_at {datetime}' => '于 {datetime} 发布',\n    'reply_at {datetime}' => '于 {datetime} 回复',\n    'last_by' => '最后由',\n\n];"
  },
  {
    "path": "common/models/LoginForm.php",
    "content": "<?php\nnamespace common\\models;\n\nuse Yii;\nuse yii\\base\\Model;\n\n/**\n * Login form\n */\nclass LoginForm extends Model\n{\n    public $username;\n    public $password;\n    public $rememberMe = true;\n    private $_user = false;\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            // username and password are both required\n            [['username', 'password'], 'required'],\n            // rememberMe must be a boolean value\n            ['rememberMe', 'boolean'],\n            // password is validated by validatePassword()\n            ['password', 'validatePassword'],\n        ];\n    }\n\n    /**\n     * Validates the password.\n     * This method serves as the inline validation for password.\n     *\n     * @param string $attribute the attribute currently being validated\n     * @param array $params the additional name-value pairs given in the rule\n     */\n    public function validatePassword($attribute, $params)\n    {\n        if (!$this->hasErrors()) {\n            $user = $this->getUser();\n            if (!$user || !$user->validatePassword($this->password)) {\n                $this->addError($attribute, Yii::t('common', 'Incorrect username or password.'));\n            }\n        }\n    }\n\n    /**\n     * Logs in a user using the provided username and password.\n     *\n     * @return boolean whether the user is logged in successfully\n     */\n    public function login()\n    {\n        if ($this->validate()) {\n            return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'username' => Yii::t('common', 'Username'),\n            'password' => Yii::t('common', 'Password'),\n            'rememberMe' => Yii::t('common', 'Remember Me'),\n        ];\n    }\n\n    /**\n     * email 邮箱登录\n     * @user onyony\n     * @return bool|null|static\n     */\n    public function getUser()\n    {\n        if ($this->_user === false) {\n            if (strpos($this->username, \"@\"))\n                $this->_user = User::findByEmail($this->username); //email 登录\n            else\n                $this->_user = User::findByUsername($this->username);\n        }\n\n        return $this->_user;\n    }\n\n    /**\n     * 登陆之后更新用户资料\n     * @return bool\n     */\n    public function updateUserInfo()\n    {\n        /** @var UserInfo $model */\n        $model = UserInfo::findOne(['user_id' => Yii::$app->user->getId()]);\n        $model->login_count += 1;\n        $model->prev_login_time = $model->last_login_time;\n        $model->prev_login_ip = $model->last_login_ip;\n        $model->last_login_time = time();\n        $model->last_login_ip = Yii::$app->getRequest()->getUserIP();\n\n        if (!Yii::$app->session->isActive) {\n            Yii::$app->session->open();\n        }\n        $model->session_id = Yii::$app->session->id;\n        Yii::$app->session->close();\n\n        if ($model->save()) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public function loginAdmin()\n    {\n        if ($this->validate()) {\n            if (User::isSuperAdmin($this->username)) {\n                return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);\n            }\n            $this->addError('username', 'You don\\'t have permission to login.');\n        } else {\n            $this->addError('password', Yii::t('common', 'Incorrect username or password.'));\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "common/models/Nav.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\nuse yii\\helpers\\ArrayHelper;\n\n/**\n * This is the model class for table \"nav\".\n *\n * @property integer $id\n * @property string $name\n * @property string $alias\n * @property integer $order\n * @property string $created_at\n * @property string $updated_at\n */\nclass Nav extends \\yii\\db\\ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%nav}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['name','alias','order'], 'required'],\n            [['order'], 'integer'],\n            [['name', 'alias'], 'string', 'max' => 50]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => Yii::t('app', 'ID'),\n            'name' => Yii::t('app', 'Name'),\n            'alias' => Yii::t('app', 'Alias'),\n            'order' => Yii::t('app', 'Order'),\n            'created_at' => Yii::t('app', 'Created At'),\n            'updated_at' => Yii::t('app', 'Updated At'),\n        ];\n    }\n\n    public static function getNavList()\n    {\n        $data_array = ArrayHelper::map(static::find()->orderBy(['order' => SORT_ASC])->all(), 'id', 'name');\n        return $data_array;\n    }\n\n}\n"
  },
  {
    "path": "common/models/NavUrl.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\n\n/**\n * This is the model class for table \"nav_url\".\n *\n * @property integer $id\n * @property integer $nav_id\n * @property string $title\n * @property string $url\n * @property string $description\n * @property integer $order\n * @property integer $user_id\n * @property string $created_at\n * @property string $updated_at\n */\nclass NavUrl extends \\yii\\db\\ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%nav_url}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['nav_id', 'order'], 'integer'],\n            [['title', 'url', 'nav_id','order'], 'required'],\n            [['title', 'description'], 'string', 'max' => 255],\n            [['url'], 'string', 'max' => 225]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => Yii::t('app', 'ID'),\n            'nav_id' => Yii::t('app', 'Nav ID'),\n            'title' => Yii::t('app', 'Title'),\n            'url' => Yii::t('app', 'Url'),\n            'description' => Yii::t('app', 'Description'),\n            'order' => Yii::t('app', 'Order'),\n            'user_id' => Yii::t('app', 'User ID'),\n            'created_at' => Yii::t('app', 'Created At'),\n            'updated_at' => Yii::t('app', 'Updated At'),\n        ];\n    }\n\n\n}\n"
  },
  {
    "path": "common/models/Post.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse common\\components\\db\\ActiveRecord;\nuse Yii;\nuse yiier\\antiSpam\\SpamValidator;\n\n/**\n * This is the model class for table \"post\".\n *\n * @property integer $id\n * @property string $type\n * @property integer $post_meta_id\n * @property integer $user_id\n * @property string $title\n * @property string $author\n * @property string $excerpt\n * @property string $image\n * @property string $content\n * @property string|array $tags\n * @property string $last_comment_time\n * @property string $last_comment_username\n * @property integer $view_count\n * @property integer $comment_count\n * @property integer $favorite_count\n * @property integer $like_count\n * @property integer $thanks_count\n * @property integer $hate_count\n * @property integer $status\n * @property integer $order\n * @property integer $created_at\n * @property integer $updated_at\n *\n * @property PostMeta $category\n * @property User $user\n */\nclass Post extends ActiveRecord\n{\n    /**\n     * 博客文章\n     */\n    const TYPE_BLOG = 'blog';\n\n    /**\n     * 社区话题\n     */\n    const TYPE_TOPIC = 'topic';\n\n    /**\n     * 置顶\n     */\n    const STATUS_TOP = 3;\n\n    /**\n     * 推荐\n     */\n    const STATUS_EXCELLENT = 2;\n\n    /**\n     * 发布\n     */\n    const STATUS_ACTIVE = 1;\n\n    /**\n     * 删除\n     */\n    const STATUS_DELETED = 0;\n\n\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%post}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['post_meta_id', 'title', 'content'], 'required'],\n            [\n                [\n                    'post_meta_id',\n                    'user_id',\n                    'view_count',\n                    'comment_count',\n                    'last_comment_time',\n                    'favorite_count',\n                    'like_count',\n                    'thanks_count',\n                    'hate_count',\n                    'status',\n                    'order',\n                    'created_at',\n                    'updated_at'\n                ],\n                'integer'\n            ],\n            [['content'], 'string', 'min' => 2],\n            ['content', 'validateLimitPostTime'],\n            [['type'], 'string', 'max' => 32],\n            [['last_comment_username'], 'string', 'max' => 20],\n            [['title'], 'string', 'max' => 50, 'min' => 2],\n            [['excerpt', 'image'], 'string', 'max' => 255],\n            [['author'], 'string', 'max' => 100],\n            [['cc', 'tags'], 'safe'],\n            ['content', SpamValidator::className(), 'message' => '请勿发表垃圾内容'],\n            ['title', SpamValidator::className(), 'message' => '请勿发表垃圾内容'],\n        ];\n    }\n\n    /**\n     * 验证新用户是否能发帖\n     * @param $attribute\n     */\n    public function validateLimitPostTime($attribute)\n    {\n        if ($time = $this->limitPostTime()) {\n            $this->addError($attribute, \"新注册用户只能回帖，{$time}秒之后才能发帖。\");\n        }\n    }\n\n    /**\n     * 新用户N秒之后才能发帖\n     * @return bool|int\n     */\n    public function limitPostTime()\n    {\n        $userCreatedAt = Yii::$app->user->identity['created_at'];\n        $newUserPostLimit = params('newUserPostLimit');\n        if ($newUserPostLimit && time() - $userCreatedAt < $newUserPostLimit) {\n            return $newUserPostLimit - (time() - $userCreatedAt);\n        }\n        return false;\n    }\n\n    /**\n     * 限制发帖间隔\n     * @return bool|int\n     */\n    public function limitPostingIntervalTime()\n    {\n        $lastPostCreatedAt = Post::find()->select('created_at')->where(['type' => self::TYPE_TOPIC])->orderBy(['created_at' => SORT_DESC])->scalar();\n        $postingIntervalLimit = params('postingIntervalLimit');\n        if ($postingIntervalLimit && time() - $lastPostCreatedAt < $postingIntervalLimit) {\n            return $postingIntervalLimit - (time() - $lastPostCreatedAt);\n        }\n        return false;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'type' => '内容类型',\n            'post_meta_id' => '分类',\n            'category_name' => '分类',\n            'user_id' => '用户ID',\n            'username' => '用户',\n            'title' => '标题',\n            'author' => '作者',\n            'excerpt' => '摘要',\n            'image' => '封面图片',\n            'content' => '内容',\n            'tags' => '标签',\n            'last_comment_username' => '最后回复用户',\n            'last_comment_time' => '最后评论时间',\n            'view_count' => '查看数',\n            'comment_count' => '评论数',\n            'favorite_count' => '收藏数',\n            'like_count' => '喜欢数',\n            'thanks_count' => '感谢数',\n            'hate_count' => '讨厌数',\n            'status' => '状态',\n            'order' => '排序',\n            'created_at' => '创建时间',\n            'updated_at' => '修改时间',\n            'cc' => '注明版权信息（原创文章欢迎使用）',\n        ];\n    }\n\n    public function getUser()\n    {\n        return $this->hasOne(User::className(), ['id' => 'user_id']);\n    }\n\n\n    public function getUserInfo()\n    {\n        return $this->hasOne(UserInfo::className(), ['user_id' => 'user_id']);\n    }\n\n\n    public function getCategory()\n    {\n        return $this->hasOne(PostMeta::className(), ['id' => 'post_meta_id']);\n    }\n\n    public function isCurrent()\n    {\n        return $this->user_id == Yii::$app->user->id;\n    }\n\n    public function beforeSave($insert)\n    {\n        if (parent::beforeSave($insert)) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @param bool $status\n     * @return array|mixed\n     */\n    public static function getStatuses($status = false)\n    {\n        $statuses = [\n            self::STATUS_DELETED => Yii::t('common', 'DELETED'),\n            self::STATUS_ACTIVE => Yii::t('common', 'ACTIVE'),\n            self::STATUS_EXCELLENT => Yii::t('common', 'EXCELLENT'),\n            self::STATUS_TOP => Yii::t('common', 'TOP'),\n        ];\n\n        return $status !== false ? ArrayHelper::getValue($statuses, $status) : $statuses;\n    }\n\n\n}\n"
  },
  {
    "path": "common/models/PostComment.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse common\\components\\db\\ActiveRecord;\nuse common\\services\\NotificationService;\nuse common\\services\\PostService;\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\user\\models\\UserMeta;\nuse Yii;\nuse yii\\db\\Query;\nuse yii\\web\\NotFoundHttpException;\nuse yiier\\antiSpam\\SpamValidator;\n\n/**\n * This is the model class for table \"post_comment\".\n *\n * @property integer $id\n * @property string $parent\n * @property string $post_id\n * @property string $comment\n * @property integer $status\n * @property string $user_id\n * @property string $like_count\n * @property string $ip\n * @property string $created_at\n * @property string $updated_at\n *\n * @property Topic $topic\n * @property Post $post\n */\nclass PostComment extends ActiveRecord\n{\n    const TYPE = 'comment';\n    /**\n     * 发布\n     */\n    const STATUS_ACTIVE = 1;\n\n    /**\n     * 删除\n     */\n    const STATUS_DELETED = 0;\n\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%post_comment}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['parent', 'post_id', 'status', 'user_id', 'like_count', 'created_at', 'updated_at'], 'integer'],\n            [['post_id', 'comment', 'user_id', 'ip'], 'required'],\n            [['comment'], 'string', 'min' => 1],\n            ['comment', SpamValidator::className(), 'message' => '请勿发表垃圾内容'],\n            [['ip'], 'string', 'max' => 255]\n        ];\n    }\n\n    public function getUser()\n    {\n        return $this->hasOne(User::className(), ['id' => 'user_id']);\n    }\n\n    public function getPost()\n    {\n        return $this->hasOne(Post::className(), ['id' => 'post_id']);\n    }\n\n    public function getTopic()\n    {\n        return $this->hasOne(Topic::className(), ['id' => 'post_id'])->where(['type' => 'topic']);\n    }\n\n    public function getLike()\n    {\n        $model = new UserMeta();\n        return $model->isUserAction(self::TYPE, 'like', $this->id);\n    }\n\n    /**\n     * 通过ID获取指定评论\n     * @param $id\n     * @param string $condition\n     * @return array|null|\\yii\\db\\ActiveRecord|static\n     * @throws NotFoundHttpException\n     */\n    public static function findModel($id, $condition = '')\n    {\n        if (!$model = Yii::$app->cache->get('comment' . $id)) {\n            $model = static::find()\n                ->where(['id' => $id])\n                ->andWhere($condition)\n                ->one();\n        }\n        if ($model !== null) {\n            Yii::$app->cache->set('comment' . $id, $model, 0);\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n\n    /**\n     * 通过ID获取指定评论\n     * @param $id\n     * @return array|null|\\yii\\db\\ActiveRecord|static\n     * @throws NotFoundHttpException\n     */\n    public static function findComment($id)\n    {\n        return static::findModel($id, ['status' => self::STATUS_ACTIVE]);\n    }\n\n    /**\n     * 获取已经删除过的评论\n     * @param $id\n     * @return array|null|\\yii\\db\\ActiveRecord\n     * @throws NotFoundHttpException\n     */\n    public static function findDeletedComment($id)\n    {\n        return static::findModel($id, ['status' => self::STATUS_DELETED]);\n    }\n\n    /**\n     * 评论列表\n     * @param $postId\n     * @return Query\n     */\n    public static function findCommentList($postId)\n    {\n        return static::find()->with('user')->where(['post_id' => $postId]);\n    }\n\n    /**\n     * 自己写的评论\n     * @return bool\n     */\n    public function isCurrent()\n    {\n        return $this->user_id == Yii::$app->user->id;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'parent' => '父级评论',\n            'post_id' => '文章ID',\n            'comment' => '评论',\n            'status' => '1为正常 0为禁用',\n            'user_id' => '用户ID',\n            'like_count' => '喜欢数',\n            'ip' => '评论者ip地址',\n            'created_at' => '创建时间',\n            'updated_at' => '修改时间',\n        ];\n    }\n\n    public $atUsers;\n\n    public function beforeSave($insert)\n    {\n        if (!parent::beforeSave($insert)) {\n            return false;\n        }\n\n        $this->comment = PostService::contentComment($this->comment, $this);\n        return true;\n    }\n\n    public function afterSave($insert, $changedAttributes)\n    {\n        parent::afterSave($insert, $changedAttributes);\n\n        $post = $this->topic;\n\n        (new UserMeta())->saveNewMeta('topic', $this->post_id, 'follow');\n        (new NotificationService())->newReplyNotify(\\Yii::$app->user->identity, $post, $this, $this->atUsers);\n        // 更新回复时间\n        $post->lastCommentToUpdate(\\Yii::$app->user->identity->username);\n        if ($insert) {\n            // 评论计数器\n            Topic::updateAllCounters(['comment_count' => 1], ['id' => $post->id]);\n            // 更新个人总统计\n            UserInfo::updateAllCounters(['comment_count' => 1], ['user_id' => $this->user_id]);\n        }\n\n        \\Yii::$app->cache->set('comment' . $this->id, $this, 0);\n\n    }\n}\n"
  },
  {
    "path": "common/models/PostMeta.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse DevGroup\\TagDependencyHelper\\CacheableActiveRecord;\nuse DevGroup\\TagDependencyHelper\\NamingHelper;\nuse DevGroup\\TagDependencyHelper\\TagDependencyTrait;\nuse Yii;\nuse yii\\caching\\TagDependency;\nuse yii\\helpers\\ArrayHelper;\nuse common\\components\\db\\ActiveRecord;\n\n/**\n * This is the model class for table \"post_meta\".\n *\n * @property integer $id\n * @property string $name\n * @property string $alias\n * @property string $type\n * @property string $description\n * @property string $count\n * @property string $order\n * @property string $created_at\n * @property string $updated_at\n * @property PostMeta[] $children\n */\nclass PostMeta extends ActiveRecord\n{\n\n    use TagDependencyTrait;\n\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%post_meta}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function behaviors()\n    {\n        return ArrayHelper::merge(parent::behaviors(), [\n            'class' => CacheableActiveRecord::className(),\n        ]);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['count', 'order', 'created_at', 'updated_at', 'parent'], 'integer'],\n            [['name'], 'string', 'max' => 100],\n            [['alias', 'type'], 'string', 'max' => 32],\n            [['description'], 'string', 'max' => 255],\n            [['alias'], 'unique']\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'name' => '名称',\n            'parent' => '父级分类',\n            'alias' => '变量（别名）',\n            'type' => '项目类型',\n            'description' => '选项描述',\n            'count' => '项目所属内容个数',\n            'order' => '项目排序',\n            'created_at' => '创建时间',\n            'updated_at' => '修改时间',\n        ];\n    }\n\n    public static function blogCategory()\n    {\n\n        return ArrayHelper::map(static::find()->where(['type' => 'blog_category'])->all(), 'id', 'name');\n    }\n\n    public static function topicCategory()\n    {\n        $parents = ArrayHelper::map(\n            static::find()->where(['parent' => null])->orWhere(['parent' => 0])->orderBy(['order' => SORT_ASC])->all(),\n            'id', 'name'\n        );\n        $nodes = [];\n        foreach ($parents as $key => $value) {\n            $nodes[$value] = ArrayHelper::map(static::find()->where(['parent' => $key])->asArray()->all(), 'id', 'name');\n        }\n        return $nodes;\n    }\n\n    /**\n     * 返回无人区节点id\n     * @return PostMeta|int\n     */\n    public static function noManLandId()\n    {\n        /** @var PostMeta $postMeta */\n        $postMeta = self::find()->where(['alias' => 'no-man-land'])->one();\n        if ($postMeta) {\n            return $postMeta->id;\n        }\n        return $postMeta;\n    }\n\n    public function getChildren()\n    {\n        return $this->hasMany(self::className(), ['parent' => 'id'])->from(self::tableName() . ' p2');\n    }\n\n    public function getTypes()\n    {\n        return [\n            'topic_category' => '社区分类',\n            'blog_category' => '文章分类',\n        ];\n    }\n\n    /**\n     * @param array $conditions\n     * @return array\n     */\n    public static function getNodesMap($conditions = [])\n    {\n        return ArrayHelper::map(static::find()->where(['type' => 'topic_category'])->andFilterWhere($conditions)->all(), 'alias', 'name');\n    }\n\n    /**\n     * @return array\n     */\n    public function getParents()\n    {\n        return ArrayHelper::map(static::find()->where(['parent' => 0])->all(), 'id', 'name');\n    }\n\n    /**\n     * 获取父子节点\n     * @return array\n     */\n    public static function getNodes()\n    {\n        $cacheKey = md5(__METHOD__);\n        if (false === $nodes = \\Yii::$app->cache->get($cacheKey)) {\n            $parents = PostMeta::find()->where([PostMeta::tableName() . '.parent' => [0, null]])->joinWith('children')->orderBy(['order' => SORT_ASC])->all();\n            /*** @var  PostMeta $parent */\n            foreach ($parents as $parent) {\n                $nodes[$parent->alias] = $parent;\n            }\n            //一天缓存\n            \\Yii::$app->cache->set($cacheKey, $nodes, 86400,\n                new TagDependency([\n                    'tags' => [NamingHelper::getCommonTag(PostMeta::className())]\n                ])\n            );\n        }\n        return $nodes;\n    }\n}\n"
  },
  {
    "path": "common/models/PostMetaSearch.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\nuse common\\models\\PostMeta;\n\n/**\n * PostMetaSearch represents the model behind the search form about `common\\models\\PostMeta`.\n */\nclass PostMetaSearch extends PostMeta\n{\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id', 'count', 'order', 'created_at', 'updated_at'], 'integer'],\n            [['name', 'alias', 'type', 'description'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * Creates data provider instance with search query applied\n     *\n     * @param array $params\n     *\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = PostMeta::find();\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n        ]);\n\n        $this->load($params);\n\n        if (!$this->validate()) {\n            // uncomment the following line if you do not want to any records when validation fails\n            // $query->where('0=1');\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'count' => $this->count,\n            'order' => $this->order,\n            'created_at' => $this->created_at,\n            'updated_at' => $this->updated_at,\n        ]);\n\n        $query->andFilterWhere(['like', 'name', $this->name])\n            ->andFilterWhere(['like', 'alias', $this->alias])\n            ->andFilterWhere(['like', 'type', $this->type])\n            ->andFilterWhere(['like', 'description', $this->description]);\n\n        return $dataProvider;\n    }\n}\n"
  },
  {
    "path": "common/models/PostSearch.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\nuse common\\models\\Post;\n\n/**\n * PostSearch represents the model behind the search form about `common\\Models\\Post`.\n */\nclass PostSearch extends Post\n{\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['user_id', 'view_count', 'comment_count', 'favorite_count', 'like_count', 'thanks_count', 'hate_count', 'status', 'order', 'created_at', 'updated_at'], 'integer'],\n            [['type', 'title', 'author', 'excerpt', 'image', 'content', 'tags', 'id', 'post_meta_id'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * @param $params\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = Post::find()->with('user', 'category');\n\n        // 如果有无人区节点 帖子列表过滤无人区节点的帖子\n        if (PostMeta::noManLandId() && (empty($params['PostSearch']['post_meta_id']) || $params['PostSearch']['post_meta_id'] != PostMeta::noManLandId())) {\n            $query->andWhere(['!=', 'post_meta_id', PostMeta::noManLandId()]);\n        }\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n            'pagination' => [\n                'pageSize' => 20,\n            ],\n            'sort' => ['defaultOrder' => [\n                'order' => SORT_ASC,\n                'last_comment_time' => SORT_DESC,\n                'created_at' => SORT_DESC,\n            ]]\n        ]);\n\n        if (!($this->load($params) && $this->validate())) {\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'post_meta_id' => $this->post_meta_id,\n            'user_id' => $this->user_id,\n            'view_count' => $this->view_count,\n            'comment_count' => $this->comment_count,\n            'favorite_count' => $this->favorite_count,\n            'like_count' => $this->like_count,\n            'thanks_count' => $this->thanks_count,\n            'hate_count' => $this->hate_count,\n            'status' => $this->status,\n            'order' => $this->order,\n            'created_at' => $this->created_at,\n            'updated_at' => $this->updated_at,\n        ]);\n\n        $query->andFilterWhere(['like', 'type', $this->type])\n            ->andFilterWhere(['like', 'title', $this->title])\n            ->andFilterWhere(['like', 'author', $this->author])\n            ->andFilterWhere(['like', 'excerpt', $this->excerpt])\n            ->andFilterWhere(['like', 'image', $this->image])\n            ->andFilterWhere(['like', 'content', $this->content])\n            ->andFilterWhere(['like', 'tags', $this->tags]);\n\n        return $dataProvider;\n    }\n}\n"
  },
  {
    "path": "common/models/PostTag.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\nuse common\\components\\db\\ActiveRecord;\n\n/**\n * This is the model class for table \"post_tag\".\n *\n * @property integer $id\n * @property string $name\n * @property string $count\n * @property string $created_at\n * @property integer $updated_at\n */\nclass PostTag extends ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%post_tag}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['count', 'created_at', 'updated_at'], 'integer'],\n            [['name'], 'string', 'max' => 20]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'name' => '名称',\n            'count' => '计数',\n            'created_at' => '创建时间',\n            'updated_at' => '修改时间',\n        ];\n    }\n}\n"
  },
  {
    "path": "common/models/PostTagSearch.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\n\n/**\n * PostTagSearch represents the model behind the search form about `common\\models\\PostTag`.\n */\nclass PostTagSearch extends PostTag\n{\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id', 'count', 'created_at', 'updated_at'], 'integer'],\n            [['name'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * Creates data provider instance with search query applied\n     *\n     * @param array $params\n     *\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = PostTag::find();\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n        ]);\n\n        $this->load($params);\n\n        if (!$this->validate()) {\n            // uncomment the following line if you do not want to any records when validation fails\n            // $query->where('0=1');\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'count' => $this->count,\n            'created_at' => $this->created_at,\n            'updated_at' => $this->updated_at,\n        ]);\n\n        $query->andFilterWhere(['like', 'name', $this->name]);\n\n        return $dataProvider;\n    }\n}\n"
  },
  {
    "path": "common/models/RightLink.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse common\\components\\db\\ActiveRecord;\nuse Yii;\n\n/**\n * This is the model class for table \"right_link\".\n *\n * @property integer $id\n * @property string $title\n * @property string $url\n * @property string $image\n * @property string $content\n * @property integer $type\n * @property string $created_user\n * @property integer $created_at\n * @property integer $updated_at\n */\nclass RightLink extends ActiveRecord\n{\n    /**\n     * 推荐资源\n     */\n    const RIGHT_LINK_TYPE_RSOURCES = 1;\n    /**\n     * 小贴士\n     */\n    const RIGHT_LINK_TYPE_TIPS = 2;\n    /**\n     * 友情链接\n     */\n    const RIGHT_LINK_TYPE_LINKS = 3;\n    /**\n     * 首页提示语\n     */\n    const RIGHT_LINK_TYPE_HEADLINE = 4;\n\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%right_link}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['title', 'created_user'], 'required'],\n            [['type', 'created_at', 'updated_at'], 'integer'],\n            [['title', 'image', 'content'], 'string', 'max' => 255],\n            [['url'], 'string', 'max' => 225],\n            [['created_user'], 'string', 'max' => 32]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'title' => '名称',\n            'url' => 'Url',\n            'image' => '图片链接',\n            'content' => '内容',\n            'type' => '展示类别',\n            'created_user' => '创建人',\n            'created_at' => 'Created At',\n            'updated_at' => 'Updated At',\n        ];\n    }\n\n    /**\n     * 分类\n     * @return array\n     */\n    public function getTypes()\n    {\n        return [\n            '1' => '推荐资源',\n            '2' => '小贴士',\n            '3' => '友情链接',\n            '4' => '首页提示语',\n        ];\n    }\n}\n"
  },
  {
    "path": "common/models/Search.php",
    "content": "<?php\r\n\r\nnamespace common\\models;\r\n\r\n\r\n/**\r\n * This is the model class for table \"topic\".\r\n *\r\n * @property integer $topic_id\r\n * @property string $title\r\n * @property string $content\r\n * @property integer $status\r\n * @property integer $updated_at\r\n */\r\nclass Search extends \\hightman\\xunsearch\\ActiveRecord\r\n{\r\n    public static function search($keyword)\r\n    {\r\n        return self::find()->where($keyword)->andWhere(['status' => [1, 2]])\r\n                ->asArray()\r\n                ->offset(0)\r\n                ->limit(1000)\r\n                ->all();\r\n    }\r\n}\r\n"
  },
  {
    "path": "common/models/SearchLog.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\n\n/**\n * This is the model class for table \"search_log\".\n *\n * @property integer $id\n * @property integer $user_id\n * @property string $keyword\n * @property integer $created_at\n */\nclass SearchLog extends \\yii\\db\\ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%search_log}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['user_id', 'created_at'], 'integer'],\n            [['keyword'], 'string', 'max' => 255]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => Yii::t('app', 'ID'),\n            'user_id' => Yii::t('app', '用户ID'),\n            'username' => Yii::t('app', '用户名'),\n            'keyword' => Yii::t('app', '搜索关键词'),\n            'created_at' => Yii::t('app', '创建时间'),\n        ];\n    }\n\n    public function getUser()\n    {\n        return $this->hasOne(User::className(), ['id' => 'user_id']);\n    }\n\n}\n"
  },
  {
    "path": "common/models/Session.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\n\n/**\n * This is the model class for table \"session\".\n *\n * @property string $id\n * @property integer $expire\n * @property resource $data\n */\nclass Session extends \\yii\\db\\ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%session}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id'], 'required'],\n            [['expire'], 'integer'],\n            [['data'], 'string'],\n            [['id'], 'string', 'max' => 40]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => Yii::t('app', 'ID'),\n            'expire' => Yii::t('app', 'Expire'),\n            'data' => Yii::t('app', 'Data'),\n        ];\n    }\n}\n"
  },
  {
    "path": "common/models/User.php",
    "content": "<?php\nnamespace common\\models;\n\nuse common\\helpers\\Avatar;\nuse Yii;\nuse yii\\base\\NotSupportedException;\nuse yii\\behaviors\\TimestampBehavior;\nuse yii\\db\\ActiveRecord;\nuse yii\\helpers\\FileHelper;\nuse yii\\web\\IdentityInterface;\nuse yiier\\merit\\models\\Merit;\nuse frontend\\modules\\user\\models\\UserAccount;\n\n/**\n * User model\n *\n * @property integer $id\n * @property string $username\n * @property string $avatar\n * @property string $password_hash\n * @property string $password_reset_token\n * @property string $email\n * @property string $auth_key\n * @property integer $role\n * @property integer $status\n * @property integer $created_at\n * @property integer $updated_at\n * @property string $tagline\n * @property string $password write-only password\n *\n * @property string $userAvatar\n * @property Merit $merit\n */\nclass User extends ActiveRecord implements IdentityInterface\n{\n    const STATUS_DELETED = 0;\n    const STATUS_ACTIVE = 10;\n    const ROLE_USER = 10;\n    const ROLE_ADMIN = 20;\n    const ROLE_SUPER_ADMIN = 30;\n\n    use \\DevGroup\\TagDependencyHelper\\TagDependencyTrait;\n\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%user}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function behaviors()\n    {\n        return [\n            TimestampBehavior::className(),\n            'CacheableActiveRecord' => [\n                'class' => \\DevGroup\\TagDependencyHelper\\CacheableActiveRecord::className(),\n            ],\n        ];\n    }\n\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            ['status', 'default', 'value' => self::STATUS_ACTIVE],\n            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],\n\n            ['role', 'default', 'value' => 10],\n            ['role', 'in', 'range' => [self::ROLE_USER, self::ROLE_ADMIN, self::ROLE_SUPER_ADMIN]],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public static function findIdentity($id)\n    {\n        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public static function findIdentityByAccessToken($token, $type = null)\n    {\n        throw new NotSupportedException('\"findIdentityByAccessToken\" is not implemented.');\n    }\n\n    /**\n     * Finds user by username\n     *\n     * @param string $username\n     * @return static|null\n     */\n    public static function findByUsername($username)\n    {\n        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);\n    }\n\n    /**\n     * 邮箱登录\n     * @user onyony\n     * @param $email\n     * @return null|static\n     */\n    public static function findByEmail($email)\n    {\n        return static::findOne(['email' => $email, 'status' => self::STATUS_ACTIVE]);\n    }\n\n    /**\n     * Finds user by password reset token\n     *\n     * @param string $token password reset token\n     * @return static|null\n     */\n    public static function findByPasswordResetToken($token)\n    {\n        if (!static::isPasswordResetTokenValid($token)) {\n            return null;\n        }\n\n        return static::findOne([\n            'password_reset_token' => $token,\n            'status' => self::STATUS_ACTIVE,\n        ]);\n    }\n\n    /**\n     * Finds out if password reset token is valid\n     *\n     * @param string $token password reset token\n     * @return boolean\n     */\n    public static function isPasswordResetTokenValid($token)\n    {\n        if (empty($token)) {\n            return false;\n        }\n        $expire = Yii::$app->params['user.passwordResetTokenExpire'];\n        $parts = explode('_', $token);\n        $timestamp = (int)end($parts);\n        return $timestamp + $expire >= time();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getId()\n    {\n        return $this->getPrimaryKey();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function getAuthKey()\n    {\n        return $this->auth_key;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function validateAuthKey($authKey)\n    {\n        return $this->getAuthKey() === $authKey;\n    }\n\n    /**\n     * Validates password\n     *\n     * @param string $password password to validate\n     * @return boolean if password provided is valid for current user\n     */\n    public function validatePassword($password)\n    {\n        return Yii::$app->security->validatePassword($password, $this->password_hash);\n    }\n\n    /**\n     * Generates password hash from password and sets it to the model\n     *\n     * @param string $password\n     */\n    public function setPassword($password)\n    {\n        $this->password_hash = Yii::$app->security->generatePasswordHash($password);\n    }\n\n    /**\n     * Generates \"remember me\" authentication key\n     */\n    public function generateAuthKey()\n    {\n        $this->auth_key = Yii::$app->security->generateRandomString();\n    }\n\n    /**\n     * Generates new password reset token\n     */\n    public function generatePasswordResetToken()\n    {\n        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();\n    }\n\n    /**\n     * Removes password reset token\n     */\n    public function removePasswordResetToken()\n    {\n        $this->password_reset_token = null;\n    }\n\n    /**\n     * 获取用户头像\n     * @param int $size\n     * @return string\n     * @throws \\yii\\base\\Exception\n     */\n    public function getUserAvatar($size = 50)\n    {\n        if ($this->avatar) {\n            // TODO 写法更优雅\n            $avatarPath = Yii::$app->basePath . Yii::$app->params['avatarPath'];\n            $avatarCachePath = Yii::$app->basePath . Yii::$app->params['avatarCachePath'];\n            FileHelper::createDirectory($avatarCachePath); // 创建文件夹\n            if (file_exists($avatarCachePath . $size . '_' . $this->avatar)) {\n                // 缓存头像是否存在\n                return Yii::$app->params['avatarCacheUrl'] . $size . '_' . $this->avatar;\n            }\n            if (file_exists($avatarPath . $this->avatar)) {\n                // 原始头像是否存在\n                \\yii\\imagine\\Image::thumbnail($avatarPath . $this->avatar, $size, $size)\n                    ->save($avatarCachePath . $size . '_' . $this->avatar, ['quality' => 100]);\n                return Yii::$app->params['avatarCacheUrl'] . $size . '_' . $this->avatar;\n            }\n        }\n        return (new Avatar($this->email, $size))->getAvater();\n    }\n\n    public function getUserInfo()\n    {\n        return $this->hasOne(UserInfo::className(), ['user_id' => 'id']);\n    }\n\n    public function getMerit()\n    {\n        return $this->hasOne(Merit::className(), ['user_id' => 'id']);\n    }\n\n    /**\n     * @return array\n     */\n    public function getAccounts()\n    {\n        $connected = [];\n        $accounts = $this->hasMany(UserAccount::className(), ['user_id' => 'id'])->all();\n\n        // @var Account $account\n        foreach ($accounts as $account) {\n            $connected[$account->provider] = $account;\n        }\n\n        return $connected;\n    }\n\n    /** @inheritdoc */\n    public function afterSave($insert, $changedAttributes)\n    {\n        if ($insert) {\n            $time = time();\n            $ip = isset(Yii::$app->request->userIP) ? Yii::$app->request->userIP : '127.0.0.1';\n            $userInfo = Yii::createObject([\n                'class' => UserInfo::className(),\n                'user_id' => $this->id,\n                'prev_login_time' => $time,\n                'prev_login_ip' => $ip,\n                'last_login_time' => $time,\n                'last_login_ip' => $ip,\n                'created_at' => $time,\n                'updated_at' => $time,\n            ]);\n            $userInfo->save();\n        }\n        parent::afterSave($insert, $changedAttributes);\n    }\n\n\n    public static function isAdmin($username)\n    {\n        if (static::findOne(['username' => $username, 'role' => self::ROLE_ADMIN])) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public static function isSuperAdmin($username)\n    {\n        if (static::findOne(['username' => $username, 'role' => self::ROLE_SUPER_ADMIN])) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @return bool\n     */\n    public static function currUserIsSuperAdmin()\n    {\n        return user()->identity && Yii::$app->user->identity->role == self::ROLE_SUPER_ADMIN;\n    }\n\n    /**\n     * 获取权限\n     * @param $username\n     * @return bool\n     */\n    public static function getThrones($username = '')\n    {\n        if (!$username && Yii::$app->user->id) {\n            $username = Yii::$app->user->identity->username;\n        } else {\n            return false;\n        }\n        if ($isAdmin = self::isAdmin($username)) {\n            return $isAdmin;\n        }\n        return self::isSuperAdmin($username);\n    }\n\n    public static function getRole($role)\n    {\n        $data = [\n            self::ROLE_ADMIN => [\n                'name' => '高级会员',\n                'color' => 'primary',\n            ],\n            self::ROLE_USER => [\n                'name' => '会员',\n                'color' => 'info',\n            ],\n            self::ROLE_SUPER_ADMIN => [\n                'name' => '管理员',\n                'color' => 'success',\n            ]\n        ];\n        return $data[$role];\n    }\n\n    public static function getRoleList()\n    {\n        return [\n            self::ROLE_ADMIN => '高级会员',\n            self::ROLE_USER => '会员',\n            self::ROLE_SUPER_ADMIN => '管理员',\n        ];\n    }\n\n    public static function getStatus($status)\n    {\n        $data = [\n            self::STATUS_DELETED => [\n                'name' => '已删除',\n                'color' => 'danger',\n            ],\n            self::STATUS_ACTIVE => [\n                'name' => '正常',\n                'color' => 'default',\n            ],\n        ];\n\n        return $data[$status];\n    }\n\n    public static function getStatusList()\n    {\n        return [\n            self::STATUS_DELETED => '已删除',\n            self::STATUS_ACTIVE => '正常',\n        ];\n    }\n}\n"
  },
  {
    "path": "common/models/UserInfo.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\nuse common\\components\\db\\ActiveRecord;\n\n/**\n * This is the model class for table \"user_info\".\n *\n * @property integer $id\n * @property string $user_id\n * @property string $info\n * @property string $github\n * @property string $website\n * @property string $company\n * @property string $location\n * @property integer $view_count\n * @property integer $comment_count\n * @property integer $post_count\n * @property integer $thanks_count\n * @property integer $like_count\n * @property integer $hate_count\n * @property integer $login_count\n * @property string $prev_login_time\n * @property string $prev_login_ip\n * @property string $last_login_time\n * @property string $last_login_ip\n * @property string $created_at\n * @property string $updated_at\n */\nclass UserInfo extends ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%user_info}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['user_id', 'prev_login_time', 'prev_login_ip', 'last_login_time', 'last_login_ip', 'created_at', 'updated_at'], 'required'],\n            [['user_id', 'view_count', 'comment_count', 'post_count', 'thanks_count', 'like_count', 'hate_count', 'login_count', 'prev_login_time', 'last_login_time', 'created_at', 'updated_at'], 'integer'],\n            [['info'], 'string', 'max' => 255],\n            [['github', 'website'], 'string', 'max' => 100],\n            [['company'], 'string', 'max' => 40],\n            [['location'], 'string', 'max' => 10],\n            [['prev_login_ip', 'last_login_ip'], 'string', 'max' => 32]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'user_id' => 'User ID',\n            'info' => '会员简介',\n            'github' => 'GitHub 帐号',\n            'website' => '个人主页',\n            'company' => '公司',\n            'location' => '城市',\n            'view_count' => '个人主页浏览次数',\n            'comment_count' => '发布评论数',\n            'post_count' => '发布文章数',\n            'thanks_count' => '被感谢次数',\n            'like_count' => '被赞次数',\n            'hate_count' => '喝倒彩次数',\n            'login_count' => '登录次数',\n            'prev_login_time' => '上次登录时间',\n            'prev_login_ip' => '上次登录IP',\n            'last_login_time' => '最后登录时间',\n            'last_login_ip' => '最后登录IP',\n            'created_at' => 'Created At',\n            'updated_at' => 'Updated At',\n        ];\n    }\n}\n"
  },
  {
    "path": "common/models/UserSearch.php",
    "content": "<?php\n\nnamespace common\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\nuse common\\models\\User;\n\n/**\n * UserSearch represents the model behind the search form about `common\\models\\User`.\n */\nclass UserSearch extends User\n{\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id', 'role', 'status', 'created_at', 'updated_at'], 'integer'],\n            [['username', 'avatar', 'auth_key', 'password_hash', 'password_reset_token', 'email', 'tagline'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * Creates data provider instance with search query applied\n     *\n     * @param array $params\n     *\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = User::find();\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n        ]);\n\n        $this->load($params);\n\n        if (!$this->validate()) {\n            // uncomment the following line if you do not want to any records when validation fails\n            // $query->where('0=1');\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'role' => $this->role,\n            'status' => $this->status,\n            'created_at' => $this->created_at,\n            'updated_at' => $this->updated_at,\n        ]);\n\n        $query->andFilterWhere(['like', 'username', $this->username])\n            ->andFilterWhere(['like', 'avatar', $this->avatar])\n            ->andFilterWhere(['like', 'auth_key', $this->auth_key])\n            ->andFilterWhere(['like', 'password_hash', $this->password_hash])\n            ->andFilterWhere(['like', 'password_reset_token', $this->password_reset_token])\n            ->andFilterWhere(['like', 'email', $this->email])\n            ->andFilterWhere(['like', 'tagline', $this->tagline]);\n\n        return $dataProvider;\n    }\n}\n"
  },
  {
    "path": "common/services/CommentService.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午3:20\n * description:\n */\n\nnamespace common\\services;\n\nuse common\\models\\PostComment;\n\nclass CommentService\n{\n\n    public function userDoAction($id, $action)\n    {\n        $comment = PostComment::findComment($id);\n        $user = \\Yii::$app->user->getIdentity();\n        if (in_array($action, ['like'])) {\n            return UserService::CommentAction($user, $comment, $action);\n        }\n    }\n\n    /**\n     * 过滤内容\n     */\n    public function filterSame($content)\n    {\n        $content = strtolower($content);\n        $content = trim($content);\n        $data = ['test', '测试'];\n        if (in_array($content, $data)) {\n            return false;\n        }\n        $action = ['+1', '赞', '很赞' , '喜欢', '收藏', 'mark', '写的不错', '不错', '给力', '顶', '沙发', '前排', '留名', '路过'];\n        if (in_array($content, $action)) {\n            return false;\n        }\n        return true;\n    }\n\n}"
  },
  {
    "path": "common/services/NotificationService.php",
    "content": "<?php\r\n/**\r\n * author     : forecho <caizh@snsshop.com>\r\n * createTime : 2015/4/21 16:56\r\n * description:\r\n */\r\n\r\nnamespace common\\services;\r\n\r\nuse common\\models\\PostComment;\r\nuse common\\models\\User;\r\nuse frontend\\models\\Notification;\r\nuse frontend\\modules\\topic\\models\\Topic;\r\nuse common\\models\\Post;\r\nuse frontend\\modules\\user\\models\\UserMeta;\r\nuse yii\\base\\Exception;\r\nuse yii\\helpers\\VarDumper;\r\n\r\nclass NotificationService\r\n{\r\n    public $notifiedUsers = [];\r\n\r\n    /**\r\n     * 评论和@用户会有通知\r\n     * @param User $fromUser\r\n     * @param Topic $topic\r\n     * @param PostComment $comment\r\n     * @param $atUsers\r\n     */\r\n    public function newReplyNotify(User $fromUser, Topic $topic, PostComment $comment, $atUsers)\r\n    {\r\n        $users = [];\r\n        foreach ($topic->follower as $key => $value) {\r\n            $users[$value->user_id] = $value->user_id;\r\n        }\r\n\r\n        // Notify mentioned users\r\n        if (!$this->batchNotify('at', $fromUser, $atUsers, $topic, $comment)) {\r\n            // 通知关注的用户\r\n            $this->batchNotify('new_comment', $fromUser, $users, $topic, $comment);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 内容@用户会有通知\r\n     * @param User $fromUser\r\n     * @param Post $post\r\n     * @param [] $users\r\n     * @throws Exception\r\n     */\r\n    public function newPostNotify(User $fromUser, Post $post, $users)\r\n    {\r\n        $this->batchNotify('at_' . $post->type, $fromUser, $users, $post);\r\n    }\r\n\r\n    /**\r\n     * 点赞和其他动作通知\r\n     * @param $type\r\n     * @param $fromUserId\r\n     * @param $toUserId\r\n     * @param Post $post\r\n     * @param PostComment $comment\r\n     * @throws Exception\r\n     */\r\n    public function newActionNotify($type, $fromUserId, $toUserId, Post $post, PostComment $comment = null)\r\n    {\r\n\r\n        $model = new Notification();\r\n\r\n        $model->setAttributes([\r\n            'from_user_id' => $fromUserId,\r\n            'user_id' => $toUserId,\r\n            'post_id' => $post->id,\r\n            'comment_id' => $comment ? $comment->id : 0,\r\n            'data' => $comment ? $comment->comment : $post->content,\r\n            'type' => $type,\r\n        ]);\r\n\r\n        if ($model->save()) {\r\n            User::updateAllCounters(['notification_count' => 1], ['id' => $toUserId]);\r\n        } else {\r\n            throw new Exception(array_values($model->getFirstErrors())[0]);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * 批量处理通知\r\n     * @param $type\r\n     * @param User $fromUser\r\n     * @param $users\r\n     * @param Post $post\r\n     * @param PostComment $comment\r\n     * @return bool\r\n     * @throws Exception\r\n     */\r\n    public function batchNotify($type, User $fromUser, $users, Post $post, PostComment $comment = null)\r\n    {\r\n        foreach ($users as $key => $value) {\r\n            if ($fromUser->id == $key) {\r\n                continue;\r\n            }\r\n            $model = new Notification();\r\n            $model->setAttributes([\r\n                'from_user_id' => $fromUser->id,\r\n                'user_id' => $key,\r\n                'post_id' => $post->id,\r\n                'comment_id' => $comment ? $comment->id : 0,\r\n                'data' => self::getNotifyData($type, $comment ? $comment->comment : $post->content),\r\n                'type' => $type,\r\n            ]);\r\n            $this->notifiedUsers[] = $key;\r\n            if ($model->save()) {\r\n                User::updateAllCounters(['notification_count' => 1], ['id' => $key]);\r\n            } else {\r\n                throw new Exception(array_values($model->getFirstErrors())[0]);\r\n            }\r\n        }\r\n        return count($this->notifiedUsers);\r\n    }\r\n\r\n    /**\r\n     * 查找用户的动作通知\r\n     * @param UserMeta $meta\r\n     * @return null|Notification\r\n     */\r\n    public function findUserActionNotify(UserMeta $meta)\r\n    {\r\n        if ($meta->target_type == 'comment') {\r\n            $condition['comment_id'] = $meta->target_id;\r\n        } else {\r\n            $condition['post_id'] = $meta->target_id;\r\n        }\r\n        return Notification::findOne([\r\n                'from_user_id' => $meta->user_id,\r\n                'type' => $meta->target_type . '_' . $meta->type,\r\n            ] + $condition);\r\n    }\r\n\r\n    /**\r\n     * @param $type\r\n     * @param $data\r\n     * @return string\r\n     */\r\n    public static function getNotifyData($type, $data)\r\n    {\r\n        if (in_array($type, ['topic_like', 'topic_favorite', 'topic_thanks', 'at_topic'])) {\r\n            return '';\r\n        }\r\n        return $data;\r\n    }\r\n}"
  },
  {
    "path": "common/services/PostService.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午3:20\n * description:\n */\n\nnamespace common\\services;\n\n\nuse common\\models\\PostMeta;\nuse common\\models\\PostSearch;\nuse common\\models\\User;\nuse common\\models\\Post;\nuse DevGroup\\TagDependencyHelper\\NamingHelper;\nuse frontend\\models\\Notification;\nuse Yii;\nuse yii\\caching\\TagDependency;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\Url;\n\nclass PostService\n{\n\n    /**\n     * 删除帖子\n     * @param Post $post\n     */\n    public static function delete(Post $post)\n    {\n        $post->setAttributes(['status' => Post::STATUS_DELETED]);\n        $post->save();\n        Notification::updateAll(['status' => Post::STATUS_DELETED], ['post_id' => $post->id]);\n    }\n\n    /**\n     * 过滤内容\n     * @param $content\n     * @return bool\n     */\n    public function filterContent($content)\n    {\n        $content = strtolower($content);\n        $content = trim($content);\n        $data = ['test', '测试'];\n        if (in_array($content, $data)) {\n            return false;\n        }\n//        $action = ['+1', '赞', '很赞', '喜欢', '收藏', 'mark', '写的不错', '不错', '给力'];\n//        if (in_array($content, $action)) {\n//            return false;\n//        }\n        return true;\n    }\n\n    public static function contentTopic($content, $model)\n    {\n        $content = static::contentReplaceAtUser($content, $model);\n        return $content;\n    }\n\n    public static function contentComment($content, $model)\n    {\n        $content = static::contentReplaceAtUser($content, $model);\n        $content = static::contentReplaceFloor($content);\n        return $content;\n    }\n\n    public static function contentTweet($content, $model)\n    {\n        $content = static::contentReplaceAtUser($content, $model);\n        $content = static::contentReplaceTag($content);\n        return $content;\n    }\n\n    /**\n     * 评论内容包含 '#n楼' 的将其替换为楼层锚链接\n     * @param $content string\n     * @return string\n     */\n    public static function contentReplaceFloor($content)\n    {\n        return preg_replace('/#(\\d+)楼/', '[\\0](#comment\\1)', $content);\n    }\n\n    /**\n     * 内容包含 '@summer ' 的将其替换为用户主页链接\n     * @param $content string\n     * @return string\n     */\n    public static function contentReplaceAtUser($content, $model)\n    {\n        $model->atUsers = $usernames = static::parseUsername($content);\n        foreach ($usernames as $username) {\n            $content = str_replace(\"@$username\", sprintf('[@%s](%s)', $username, Url::to(['/user/default/show', 'username' => $username])), $content);\n        }\n\n        return $content;\n    }\n\n    public static function parseUsername($content)\n    {\n        preg_match_all('/@(\\S{4,255}) /', $content, $matches);\n        if (empty($matches[1])) {\n            return [];\n        }\n        $existUserRows = User::find()->where(['username' => $matches[1]])->select('id,username')->asArray()->all();\n        return ArrayHelper::map($existUserRows, 'id', 'username') ?: [];\n    }\n\n    public static function contentReplaceTag($content)\n    {\n        $content = preg_replace_callback('/#(\\S+?)#/', function ($matches) {\n            $tagName = $matches[1];\n            return sprintf('[%s](%s)', \"#$tagName#\", Url::to(['/tweet/default/index', 'topic' => $tagName]));\n        }, $content);\n\n        return $content;\n    }\n\n    /**\n     * @param $params\n     * @return array\n     */\n    public static function search($params)\n    {\n        $searchModel = new PostSearch();\n\n\n        // 话题或者分类筛选\n        empty($params['tag']) ?: $params['PostSearch']['tags'] = $params['tag'];\n        if (isset($params['node'])) {\n            $postMeta = PostMeta::findOne(['alias' => $params['node']]);\n            ($postMeta) ? $params['PostSearch']['post_meta_id'] = $postMeta->id : null;\n        }\n\n        if (isset($params['tab'])) {\n            $postMeta = PostMeta::findOne(['alias' => $params['tab']]);\n            ($postMeta) ? $params['PostSearch']['post_meta_id'] = ArrayHelper::getColumn($postMeta->children, 'id') : null;\n        }\n\n        $dataProvider = $searchModel->search($params);\n        $dataProvider->query->andWhere([Post::tableName() . '.type' => 'topic', 'status' => [Post::STATUS_ACTIVE, Post::STATUS_EXCELLENT]]);\n        // 排序\n        $sort = $dataProvider->getSort();\n        $sort->attributes = array_merge($sort->attributes, [\n            'hotest' => [\n                'asc' => [\n                    'view_count' => SORT_DESC,\n                    'created_at' => SORT_DESC\n                ],\n            ],\n            'excellent' => [\n                'asc' => [\n                    'status' => SORT_DESC,\n                    'view_count' => SORT_DESC,\n                    'created_at' => SORT_DESC\n                ],\n            ],\n            'uncommented' => [\n                'asc' => [\n                    'comment_count' => SORT_ASC,\n                    'created_at' => SORT_DESC\n                ],\n            ]\n        ]);\n\n        return ['searchModel' => $searchModel, 'dataProvider' => $dataProvider];\n    }\n}"
  },
  {
    "path": "common/services/TopicService.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午3:20\n * description:\n */\n\nnamespace common\\services;\n\nuse common\\models\\User;\nuse frontend\\modules\\topic\\models\\Topic;\n\nclass TopicService extends PostService\n{\n\n    public function userDoAction($id, $action)\n    {\n        $topic = Topic::findTopic($id);\n        /** @var User $user */\n        $user = \\Yii::$app->user->getIdentity();\n        if (in_array($action, ['like', 'hate'])) {\n            return UserService::TopicActionA($user, $topic, $action);\n        } else {\n            return UserService::TopicActionB($user, $topic, $action);\n        }\n    }\n\n    /**\n     * 撤销帖子\n     * @param Topic $topic\n     */\n    public static function revoke(Topic $topic)\n    {\n        $topic->setAttributes(['status' => Topic::STATUS_ACTIVE]);\n        $topic->save();\n    }\n\n    /**\n     * 加精华\n     * @param Topic $topic\n     */\n    public static function excellent(Topic $topic)\n    {\n        $action = ($topic->status == Topic::STATUS_ACTIVE) ? Topic::STATUS_EXCELLENT : Topic::STATUS_ACTIVE;\n        $topic->setAttributes(['status' => $action]);\n        $topic->save();\n    }\n}"
  },
  {
    "path": "common/services/TweetService.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午3:20\n * description:\n */\n\nnamespace common\\services;\n\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\tweet\\models\\Tweet;\nuse yii\\helpers\\Url;\n\nclass TweetService extends PostService\n{\n\n    public function userDoAction($id, $action)\n    {\n        $topic = Tweet::findTweet($id);\n        $user = \\Yii::$app->user->getIdentity();\n        return UserService::TopicActionB($user, $topic, $action);\n    }\n\n    /**\n     * 撤销帖子\n     * @param Topic $topic\n     */\n    public static function revoke(Topic $topic)\n    {\n        $topic->setAttributes(['status' => Topic::STATUS_ACTIVE]);\n        $topic->save();\n    }\n\n    /**\n     * 加精华\n     * @param Topic $topic\n     */\n    public static function excellent(Topic $topic)\n    {\n        $action = ($topic->status == Topic::STATUS_ACTIVE) ? Topic::STATUS_EXCELLENT : Topic::STATUS_ACTIVE;\n        $topic->setAttributes(['status' => $action]);\n        $topic->save();\n    }\n\n}"
  },
  {
    "path": "common/services/UserService.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午3:20\n * description:\n */\n\nnamespace common\\services;\n\nuse common\\models\\Post;\nuse common\\models\\PostComment;\nuse common\\models\\User;\nuse common\\models\\UserInfo;\nuse DevGroup\\TagDependencyHelper\\NamingHelper;\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\user\\models\\UserMeta;\nuse yii\\caching\\TagDependency;\n\nclass UserService\n{\n    /**\n     * 获取通知条数\n     * @return mixed\n     */\n    public static function findNotifyCount()\n    {\n        $user = \\Yii::$app->getUser()->getIdentity();\n        return $user ? $user->notification_count : null;\n    }\n\n    /**\n     * 清除通知数\n     * @return mixed\n     */\n    public static function clearNotifyCount()\n    {\n        return User::updateAll(['notification_count' => '0'], ['id' => \\Yii::$app->user->id]);\n    }\n\n    /**\n     * 赞话题(如果已经赞,则取消赞)\n     * @param User $user\n     * @param Topic $topic\n     * @param $action 动作\n     * @return array\n     */\n    public static function TopicActionA(User $user, Topic $topic, $action)\n    {\n        return self::toggleType($user, $topic, $action);\n    }\n\n    /**\n     * 用户对话题其他动作\n     * @param User $user\n     * @param Post $model\n     * @param $action  fa\n     * @return array\n     */\n    public static function TopicActionB(User $user, Post $model, $action)\n    {\n        $data = [\n            'target_id' => $model->id,\n            'target_type' => $model->type,\n            'user_id' => $user->id,\n            'value' => '1',\n        ];\n        if (!UserMeta::deleteOne($data + ['type' => $action])) { // 删除数据有行数则代表有数据,无行数则添加数据\n            $userMeta = new UserMeta();\n            $userMeta->setAttributes($data + ['type' => $action]);\n            $result = $userMeta->save();\n            if ($result) {\n                $model->updateCounters([$action . '_count' => 1]);\n                if ($action == 'thanks') {\n                    UserInfo::updateAllCounters([$action . '_count' => 1], ['user_id' => $model->user_id]);\n                }\n            }\n            return [$result, $userMeta];\n        }\n        $model->updateCounters([$action . '_count' => -1]);\n        if ($action == 'thanks') {\n            UserInfo::updateAllCounters([$action . '_count' => -1], ['user_id' => $model->user_id]);\n        }\n\n        return [true, null];\n    }\n\n    /**\n     * 对评论点赞\n     * @param User $user\n     * @param PostComment $comment\n     * @param $action\n     * @return array\n     */\n    public static function CommentAction(User $user, PostComment $comment, $action)\n    {\n        $data = [\n            'target_id' => $comment->id,\n            'target_type' => $comment::TYPE,\n            'user_id' => $user->id,\n            'value' => '1',\n        ];\n        if (!UserMeta::deleteOne($data + ['type' => $action])) { // 删除数据有行数则代表有数据,无行数则添加数据\n            $userMeta = new UserMeta();\n            $userMeta->setAttributes($data + ['type' => $action]);\n            $result = $userMeta->save();\n            if ($result) {\n                $comment->updateCounters([$action . '_count' => 1]);\n                // 更新个人总统计\n                UserInfo::updateAllCounters([$action . '_count' => 1], ['user_id' => $comment->user_id]);\n            }\n            return [$result, $userMeta];\n        }\n        $comment->updateCounters([$action . '_count' => -1]);\n        // 更新个人总统计\n        UserInfo::updateAllCounters([$action . '_count' => -1], ['user_id' => $comment->user_id]);\n        return [true, null];\n    }\n\n    /**\n     * 喝倒彩或者赞\n     * @param User $user\n     * @param Post $model\n     * @param $action 动作\n     * @return array\n     */\n    protected static function toggleType(User $user, Post $model, $action)\n    {\n        $data = [\n            'target_id' => $model->id,\n            'target_type' => $model->type,\n            'user_id' => $user->id,\n            'value' => '1',\n        ];\n        if (!UserMeta::deleteOne($data + ['type' => $action])) { // 删除数据有行数则代表有数据,无行数则添加数据\n            $userMeta = new UserMeta();\n            $userMeta->setAttributes($data + ['type' => $action]);\n            $result = $userMeta->save();\n            if ($result) { // 如果是新增数据, 删除掉Hate的同类型数据\n                $attributeName = ($action == 'like' ? 'hate' : 'like');\n                $attributes = [$action . '_count' => 1];\n                if (UserMeta::deleteOne($data + ['type' => $attributeName])) { // 如果有删除hate数据, hate_count也要-1\n                    $attributes[$attributeName . '_count'] = -1;\n                }\n                //更新版块统计\n                $model->updateCounters($attributes);\n                // 更新个人总统计\n                UserInfo::updateAllCounters($attributes, ['user_id' => $model->user_id]);\n            }\n            return [$result, $userMeta];\n        }\n        $model->updateCounters([$action . '_count' => -1]);\n        UserInfo::updateAllCounters([$action . '_count' => -1], ['user_id' => $model->user_id]);\n\n        return [true, null];\n    }\n\n\n    /**\n     * 查找活跃用户\n     * @param int $limit\n     * @return array|\\yii\\db\\ActiveRecord[]\n     */\n    public static function findActiveUser($limit = 12)\n    {\n        $cacheKey = md5(__METHOD__ . $limit);\n        if (false === $items = \\Yii::$app->cache->get($cacheKey)) {\n            $items = User::find()\n                ->joinWith(['merit', 'userInfo'])\n                ->where([User::tableName() . '.status' => 10])\n                ->orderBy(['merit' => SORT_DESC, '(like_count+thanks_count)' => SORT_DESC])\n                ->limit($limit)\n                ->all();\n            //一天缓存\n            \\Yii::$app->cache->set($cacheKey, $items, 86400,\n                new TagDependency([\n                    'tags' => [NamingHelper::getCommonTag(User::className())]\n                ])\n            );\n        }\n        return $items;\n    }\n}"
  },
  {
    "path": "common/widgets/JsBlock.php",
    "content": "<?php\r\n\r\nnamespace common\\widgets;\r\n\r\nuse yii\\web\\View;\r\nuse yii\\widgets\\Block;\r\n\r\n\r\nclass JsBlock extends Block\r\n{\r\n\r\n    /**\r\n     * @var null\r\n     */\r\n    public $key = null;\r\n    /**\r\n     * @var int\r\n     */\r\n    public $pos = View::POS_END;\r\n\r\n    /**\r\n     * Ends recording a block.\r\n     * This method stops output buffering and saves the rendering result as a named block in the view.\r\n     */\r\n    public function run()\r\n    {\r\n        $block = ob_get_clean();\r\n        if ($this->renderInPlace) {\r\n            throw new \\Exception(\"not implemented yet ! \");\r\n            // echo $block;\r\n        }\r\n        $block = trim($block);\r\n        /*\r\n        $jsBlockPattern  = '|^<script[^>]*>(.+?)</script>$|is';\r\n        if(preg_match($jsBlockPattern,$block)){\r\n            $block =  preg_replace ( $jsBlockPattern , '${1}'  , $block );\r\n        }\r\n        */\r\n        $jsBlockPattern = '|^<script[^>]*>(?P<block_content>.+?)</script>$|is';\r\n        if (preg_match($jsBlockPattern, $block, $matches)) {\r\n            $block = $matches['block_content'];\r\n        }\r\n\r\n        $this->view->registerJs($block, $this->pos, $this->key);\r\n    }\r\n}"
  },
  {
    "path": "composer.json",
    "content": "{\r\n  \"name\": \"iiyii/getyii\",\r\n  \"description\": \"Yii 2 Community\",\r\n  \"keywords\": [\r\n    \"yii2\",\r\n    \"framework\",\r\n    \"advanced\",\r\n    \"community\",\r\n    \"application template\"\r\n  ],\r\n  \"homepage\": \"https://github.com/iiYii/getyii/\",\r\n  \"type\": \"project\",\r\n  \"license\": \"BSD-3-Clause\",\r\n  \"support\": {\r\n    \"issues\": \"https://github.com/iiYii/getyii/issues?state=open\",\r\n    \"forum\": \"http://www.getyii.com/\",\r\n    \"wiki\": \"https://github.com/iiYii/getyii/wiki/\",\r\n    \"source\": \"https://github.com/iiYii/getyii\"\r\n  },\r\n  \"minimum-stability\": \"stable\",\r\n  \"require\": {\r\n    \"php\": \">=5.4.0\",\r\n    \"yiisoft/yii2\": \">=2.0.6\",\r\n    \"yiisoft/yii2-bootstrap\": \"*\",\r\n    \"yiisoft/yii2-swiftmailer\": \"*\",\r\n    \"conquer/select2\": \"*\",\r\n    \"bower-asset/highlightjs\": \"*\",\r\n    \"bower-asset/pace\": \"*\",\r\n    \"bower-asset/localforage\": \"*\",\r\n    \"bower-asset/at.js\": \"*\",\r\n    \"yiisoft/yii2-authclient\": \"*\",\r\n    \"yzalis/identicon\": \"*\",\r\n    \"funson86/yii2-setting\": \"*\",\r\n    \"yiisoft/yii2-imagine\": \"^2.0\",\r\n    \"hightman/xunsearch\": \"*@beta\",\r\n    \"yiier/yii2-backup\": \"*\",\r\n    \"kop/yii2-scroll-pager\": \"dev-master\",\r\n    \"devgroup/yii2-tag-dependency-helper\": \"*\",\r\n    \"yiier/yii2-return-url\": \"*\",\r\n    \"yiier/yii2-merit\": \"*\",\r\n    \"yiisoft/yii2-httpclient\": \"dev-master\",\r\n    \"understeam/yii2-slack\": \"~0.1\",\r\n    \"dmstr/yii2-adminlte-asset\": \"2.*\",\r\n    \"yiier/yii2-editor.md\": \"*\",\r\n    \"2amigos/qrcode-library\": \"^1.1\",\r\n    \"yiier/yii2-anti-spam\": \"^0.2.0\",\r\n    \"ext-curl\": \"*\"\r\n  },\r\n  \"require-dev\": {\r\n    \"fxp/composer-asset-plugin\": \"^1.2.0\",\r\n    \"yiisoft/yii2-codeception\": \"*\",\r\n    \"yiisoft/yii2-debug\": \"*\",\r\n    \"yiisoft/yii2-gii\": \"*\",\r\n    \"yiisoft/yii2-faker\": \"*\"\r\n  },\r\n  \"config\": {\r\n    \"process-timeout\": 1800,\r\n    \"fxp-asset\": {\r\n      \"enabled\": false\r\n    }\r\n  },\r\n  \"autoload\": {\r\n    \"psr-4\": {\r\n      \"common\\\\\": \"common\"\r\n    },\r\n    \"files\": [\r\n      \"common/components/GlobalFunctions.php\"\r\n    ]\r\n  },\r\n  \"scripts\": {\r\n    \"post-create-project-cmd\": [\r\n      \"yii\\\\composer\\\\Installer::postCreateProject\"\r\n    ],\r\n    \"post-install-cmd\": [\r\n      \"common\\\\components\\\\ComposerInstaller::initProject\"\r\n    ],\r\n    \"post-update-cmd\": [\r\n      \"common\\\\components\\\\ComposerInstaller::initProject\"\r\n    ]\r\n  },\r\n  \"repositories\": [\r\n    {\r\n      \"type\": \"composer\",\r\n      \"url\": \"https://asset-packagist.org\"\r\n    }\r\n  ]\r\n}\r\n"
  },
  {
    "path": "console/config/.gitignore",
    "content": "main-local.php\nparams-local.php"
  },
  {
    "path": "console/config/bootstrap.php",
    "content": "<?php\n"
  },
  {
    "path": "console/config/main.php",
    "content": "<?php\n$params = array_merge(\n    require(__DIR__ . '/../../common/config/params.php'),\n    require(__DIR__ . '/../../common/config/params-local.php'),\n    require(__DIR__ . '/params.php'),\n    require(__DIR__ . '/params-local.php')\n);\n\nreturn [\n    'id' => 'app-console',\n    'basePath' => dirname(__DIR__),\n    'bootstrap' => ['log', 'gii'],\n    'controllerNamespace' => 'console\\controllers',\n    'modules' => [\n        'gii' => 'yii\\gii\\Module',\n    ],\n    'components' => [\n        'log' => [\n            'targets' => [\n                [\n                    'class' => 'yii\\log\\FileTarget',\n                    'levels' => ['error', 'warning', 'info'],\n                ],\n            ],\n        ],\n        'user' => [\n            'class' => 'yii\\web\\User',\n            'identityClass' => 'common\\models\\User',\n            //'enableAutoLogin' => true,\n        ],\n    ],\n    'params' => $params,\n    'controllerMap' => [\n        'backup' => [\n            'class' => 'yiier\\backup\\controllers\\BackupController',\n        ]\n    ]\n];\n"
  },
  {
    "path": "console/config/params.php",
    "content": "<?php\nreturn [\n    'adminEmail' => 'admin@example.com',\n];\n"
  },
  {
    "path": "console/controllers/.gitkeep",
    "content": ""
  },
  {
    "path": "console/controllers/InstallController.php",
    "content": "<?php\n\nnamespace console\\controllers;\n\nuse Yii;\nuse yii\\console\\Controller;\nuse yii\\helpers\\Console;\n\nclass InstallController extends Controller\n{\n    /**\n     * 检查当前环境是否可用\n     */\n    public function actionCheck($path = '@root/requirements.php')\n    {\n        ob_start();\n        ob_implicit_flush(false);\n        require Yii::getAlias($path);\n        $content = ob_get_clean();\n        $content = str_replace('OK', $this->ansiFormat(\"OK\", Console::FG_GREEN), $content);\n        $content = str_replace('WARNING!!!', $this->ansiFormat(\"WARNING!!!\", Console::FG_YELLOW), $content);\n        $content = str_replace('FAILED!!!', $this->ansiFormat(\"FAILED!!!\", Console::FG_RED), $content);\n        $this->stdout($content);\n    }\n\n    /**\n     * 项目安装 当代码第一次初始化后执行此命令可引导安装项目\n     */\n    public function actionIndex()\n    {\n        $lockFile = Yii::getAlias('@root/install.lock');\n        if (!file_exists($lockFile)) {\n            $result = $this->runSteps([\n                '数据库配置' => 'db',\n                '初始化数据库数据' => 'migrate'\n            ]);\n            if ($result) {\n                $this->stdout(\"恭喜, 站点配置成功!\\n\", Console::FG_GREEN);\n                touch($lockFile);\n            }\n        } else {\n            $this->stdout(\"站点已经配置完毕,无需再配置\\n\", Console::FG_GREEN);\n            $this->stdout(\" - 如需重新配置, 请删除{$lockFile}文件后再执行命令!\\n\");\n        }\n    }\n\n    public function runSteps(array $steps)\n    {\n        $i = 1;\n        foreach ($steps as $step => $args) {\n            $this->stdout(\"\\n\\n - Step {$i} {$step} \\n\");\n            $this->stdout(\"==================================================\\n\");\n            !is_array($args) && $args = (array)$args;\n            $method = array_shift($args);\n            $result = call_user_func_array([$this, 'action' . $method], $args);\n            if ($result === false) {\n                $this->stdout(\"{$step}失败, 退出安装流程\\n\", Console::FG_RED);\n                return false;\n            }\n            $i++;\n        }\n        return true;\n    }\n\n    /**\n     * 生成数据库配置文件\n     * @return mixed\n     */\n    public function actionDb()\n    {\n        $dbFile = Yii::getAlias('@common/config/db-local.php');\n        if (!file_exists($dbFile)) {\n            $this->stdout(\"默认数据库配置文件未找到,将进入数据库配置创建流程\\n\", Console::FG_RED);\n            $result = $this->generateDbFile($dbFile);\n            if ($result !== false) { // 生成文件了之后.加载db配置\n                Yii::$app->set('db', require $dbFile);\n            }\n            return $result;\n        }\n        $this->stdout(\"'{$dbFile}' 配置文件已存在, 无需配置\\n\");\n    }\n\n    /**\n     * 创建数据库配置文件\n     * @param $dbFile\n     * @return mixed\n     */\n    public function generateDbFile($dbFile)\n    {\n        $host = $this->prompt('请输入数据库主机地址:', [\n            'default' => 'localhost'\n        ]);\n        $dbName = $this->prompt('请输入数据库名称:', [\n            'default' => 'getyii'\n        ]);\n        $dbConfig = [\n            'dsn' => \"mysql:host={$host};dbname={$dbName}\",\n            'username' => $this->prompt(\"请输入数据库访问账号:\", [\n                'default' => 'root'\n            ]),\n            'password' => $this->prompt(\"请输入数据库访问密码:\"),\n            'tablePrefix' => $this->prompt(\"请输入数据库表前缀（默认不使用）:\", [\n                'default' => ''\n            ]),\n            'charset' => $this->prompt(\"请输入数据默认的字符集:\", [\n                'default' => 'utf8mb4'\n            ])\n        ];\n\n        $message = null;\n        if ($this->confirm('是否测试数据库可用?', true)) {\n            $db = Yii::createObject(array_merge([\n                'class' => 'yii\\db\\Connection'\n            ], $dbConfig));\n            try {\n                $db->open();\n                $this->stdout(\"数据连接成功\\n\", Console::FG_GREEN);\n            } catch (\\Exception $e) {\n                $this->stdout(\"数据连接失败:\" . $e->getMessage() . \"\\n\", Console::FG_RED);\n                $message = '依然写入文件?(如果依然写入文件, 会影响后续安装步骤)';\n            }\n        }\n        if ($message === null || $this->confirm($message)) {\n            $this->stdout(\"生成数据库配置文件...\\n\");\n            $code = <<<EOF\n<?php\nreturn [\n    'class' => 'yii\\db\\Connection',\n    'dsn' => '{$dbConfig['dsn']}',\n    'username' => '{$dbConfig['username']}',\n    'password' => '{$dbConfig['password']}',\n    'tablePrefix' => '{$dbConfig['tablePrefix']}',\n    'charset' => '{$dbConfig['charset']}',\n];\nEOF;\n            file_put_contents($dbFile, $code);\n            $this->stdout(\"恭喜! 数据库配置完毕!\\n\", Console::FG_GREEN);\n        } elseif ($this->confirm(\"是否重新设置?\", true)) {\n            return $this->generateDbFile($dbFile);\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 生成数据库结构和数据\n     */\n    public function actionMigrate()\n    {\n        $this->stdout(\"\\n开始迁移数据库结构和数据\\n\", Console::FG_GREEN);\n        $this->stdout(\"** 如无特殊需求,当询问是否迁移数据是回复yes既可 **\\n\", Console::FG_RED);\n        // 默认迁移目录\n        $migrationsPath = array(\n            '默认目录' => Yii::getAlias('@console/migrations')\n        );\n\n        foreach ($migrationsPath as $name => $migrationPath) {\n            if (!is_dir($migrationPath)) {\n                continue;\n            }\n            $this->stdout(\"\\n\\n{$name}迁移: {$migrationPath}\\n\", Console::FG_YELLOW);\n            Yii::$app->runAction('migrate/up', [\n                'migrationPath' => $migrationPath\n            ]);\n        }\n    }\n}\n"
  },
  {
    "path": "console/controllers/SyncController.php",
    "content": "<?php\n\nnamespace console\\controllers;\n\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\user\\models\\UserMeta;\nuse Yii;\nuse common\\models\\PostComment;\nuse common\\models\\UserInfo;\nuse yii\\console\\Controller;\nuse yii\\db\\Expression;\nuse yii\\db\\Query;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\VarDumper;\n\n\nclass SyncController extends Controller\n{\n    public function actionUserInfo()\n    {\n        UserInfo::updateAll(['thanks_count' => 0, 'like_count' => 0, 'hate_count' => 0]);\n        $meta = UserMeta::find()->all();\n        foreach ($meta as $key => $value) {\n            if (in_array($value->type, ['thanks', 'like', 'hate'])) {\n                switch ($value->target_type) {\n                    case 'topic':\n                    case 'post':\n                        $this->stdout(\"同步文章操作……\\n\");\n                        $topic = Topic::findOne($value->target_id);\n                        if (UserInfo::updateAllCounters([$value->type . '_count' => 1], ['user_id' => $topic->user_id])) {\n                            $this->stdout(\"同步评论成功`(*∩_∩*)′\\n\");\n                        } else {\n                            $this->stdout(\"同步评论失败::>_<::\\n\");\n                        }\n                        break;\n\n                    case 'comment':\n                        $this->stdout(\"同步评论操作……\\n\");\n                        $comment = PostComment::findOne($value->target_id);\n                        if (UserInfo::updateAllCounters([$value->type . '_count' => 1], ['user_id' => $comment->user_id])) {\n                            $this->stdout(\"同步评论成功`(*∩_∩*)′\\n\");\n                        } else {\n                            $this->stdout(\"同步评论失败::>_<:: \\n\");\n                        }\n                        break;\n\n                    default:\n                        # code...\n                        break;\n                }\n            }\n        }\n        return;\n    }\n\n    public function actionPost()\n    {\n        $update = Topic::updateAll(\n            ['last_comment_time' => new Expression('created_at')],\n//            ['or', ['type' => Topic::TYPE, 'last_comment_username' => ''], ['type' => Topic::TYPE, 'last_comment_username' => null]]\n            ['and', ['type' => Topic::TYPE], ['or', ['last_comment_username' => ''], ['last_comment_username' => null]]]\n        );\n        $this->stdout(\"同步最后回复时间，同步{$update}条数据\\n\");\n\n        $subQuery = new Query();\n        $subQuery->from(PostComment::tableName())->where(['status' => PostComment::STATUS_ACTIVE])->orderBy(['created_at' => SORT_DESC]);\n        $comment = PostComment::find()->from(['tmpA' => $subQuery])\n            ->groupBy('post_id')\n            ->all();\n\n        Topic::updateAll(['comment_count' => 0], ['type' => Topic::TYPE]);\n\n        $updateComment = [];\n        foreach ($comment as $value) {\n            $commentCount = PostComment::find()->where(['post_id' => $value->post_id, 'status' => PostComment::STATUS_ACTIVE])->count();\n            $updateComment[] = Topic::updateAll(\n                [\n                    'last_comment_time' => $value->created_at,\n                    'last_comment_username' => $value->user->username,\n                    'comment_count' => $commentCount,\n                ],\n                ['id' => $value->post_id, 'type' => Topic::TYPE]\n            );\n        }\n        $this->stdout(\"校正最后回复时间和回复会员还有评论条数，校正\" . count($updateComment) . \"条数据\\n\");\n    }\n}\n"
  },
  {
    "path": "console/migrations/m130524_201442_init.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m130524_201442_init extends Migration\n{\n    public function up()\n    {\n        $this->createTable('{{%user}}', [\n            'id' => Schema::TYPE_PK,\n            'username' => Schema::TYPE_STRING . ' NOT NULL',\n            'auth_key' => Schema::TYPE_STRING . '(32) NOT NULL',\n            'password_hash' => Schema::TYPE_STRING . ' NOT NULL',\n            'password_reset_token' => Schema::TYPE_STRING,\n            'email' => Schema::TYPE_STRING . ' NOT NULL',\n            'role' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',\n            'status' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 10',\n            'created_at' => Schema::TYPE_INTEGER . ' NOT NULL',\n            'updated_at' => Schema::TYPE_INTEGER . ' NOT NULL',\n        ], $this->tableOptions);\n    }\n\n    public function down()\n    {\n        $this->dropTable('{{%user}}');\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150104_071047_init_blog.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150104_071047_init_blog extends Migration\n{\n    public function up()\n    {\n    \t// 分类\n        $tableName = '{{%post_meta}}';\n        $this->createTable($tableName, [\n            'id' => Schema::TYPE_PK,\n            'name' => Schema::TYPE_STRING . \"(100) DEFAULT NULL COMMENT '名称'\",\n            'type' => Schema::TYPE_STRING . \"(32) DEFAULT NULL COMMENT '项目类型'\",\n            'description' => Schema::TYPE_STRING . \" DEFAULT NULL COMMENT '选项描述'\",\n            'count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '项目所属内容个数'\",\n            'order' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '项目排序'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type', $tableName, 'type');\n\n        // 文章\n        $tableName = '{{%post}}';\n        $this->createTable($tableName, [\n            'id' => Schema::TYPE_PK,\n            'post_meta_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '版块ID'\",\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '作者ID'\",\n            'title' => Schema::TYPE_STRING . \" NOT NULL COMMENT '标题'\",\n            'author' => Schema::TYPE_STRING . \"(100) DEFAULT NULL COMMENT '作者'\",\n            'excerpt' => Schema::TYPE_STRING . \" DEFAULT NULL COMMENT '摘要'\",\n            'image' => Schema::TYPE_STRING . \" DEFAULT NULL COMMENT '封面图片'\",\n            'content' => Schema::TYPE_TEXT . \" NOT NULL COMMENT '内容'\",\n            'tags' => Schema::TYPE_STRING . \"(30) NOT NULL COMMENT '标签 用英文逗号隔开'\",\n            'view_count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '查看数'\",\n            'comment_count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '评论数'\",\n            'favorite_count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '收藏数'\",\n            'like_count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '喜欢数'\",\n            'thanks_count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '感谢数'\",\n            'hate_count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '讨厌数'\",\n            'status' => Schema::TYPE_BOOLEAN . \" NOT NULL DEFAULT '1' COMMENT '状态 1:发布 0：草稿'\",\n            'order' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '999' COMMENT '排序 0最大'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间'\",\n        ]);\n        $this->createIndex('post_meta_id', $tableName, 'post_meta_id');\n        $this->createIndex('tags', $tableName, 'tags');\n        $this->createIndex('user_id', $tableName, 'user_id');\n\n        // 标签表\n        $tableName = '{{%post_tag}}';\n        $this->createTable($tableName, [\n            'id' => Schema::TYPE_PK,\n            'name' => Schema::TYPE_STRING . \"(20) DEFAULT NULL COMMENT '名称'\",\n            'count' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '计数'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间'\",\n        ], $this->tableOptions);\n\n        // 评论表\n        $tableName = '{{%post_comment}}';\n        $this->createTable($tableName, [\n            'id' => Schema::TYPE_PK,\n            'parent' => Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '父级评论'\",\n            'post_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '文章ID'\",\n            'comment' => Schema::TYPE_TEXT . \" NOT NULL COMMENT '评论'\",\n            'status' => Schema::TYPE_BOOLEAN . \" NOT NULL DEFAULT '1' COMMENT '1为正常 0为禁用'\",\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '用户ID'\",\n            'ip' => Schema::TYPE_STRING . \" NOT NULL COMMENT '评论者ip地址'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('post_id', $tableName, 'post_id');\n        $this->createIndex('user_id', $tableName, 'user_id');\n    }\n\n    public function down()\n    {\n        echo \"m150104_071047_init_blog cannot be reverted.\\n\";\n        $this->dropTable('{{%post_meta}}');\n        $this->dropTable('{{%post}}');\n        $this->dropTable('{{%post_tag}}');\n        $this->dropTable('{{%post_comment}}');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150104_091352_init_user.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150104_091352_init_user extends Migration\n{\n    public function up()\n    {\n        $this->addColumn('{{%user}}', 'avatar' , Schema::TYPE_STRING . \" DEFAULT NULL COMMENT '头像' AFTER `username` \");\n\n        // 会员动作表\n        $tableName = '{{%user_meta}}';\n        $this->createTable($tableName, [\n            'id' => Schema::TYPE_PK,\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '用户ID'\",\n            'type' => Schema::TYPE_STRING . \"(100) NOT NULL DEFAULT '' COMMENT '操作类型'\",\n            'value' => Schema::TYPE_STRING . \" NOT NULL DEFAULT '' COMMENT '操作类型值'\",\n            'target_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '目标id'\",\n            'target_type' => Schema::TYPE_STRING . \"(100) NOT NULL DEFAULT '' COMMENT '目标类型'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type', $tableName, 'type');\n        $this->createIndex('user_id', $tableName, 'user_id');\n        $this->createIndex('target_id', $tableName, 'target_id');\n        $this->createIndex('target_type', $tableName, 'target_type');\n\n        // 会员第三方登录表\n        $tableName = '{{%user_auth}}';\n        $this->createTable($tableName, [\n            'id' => Schema::TYPE_PK,\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '用户ID'\",\n            'type' => Schema::TYPE_STRING . \"(100) NOT NULL DEFAULT '' COMMENT '联合登录类型'\",\n            'token' => Schema::TYPE_STRING . \" NOT NULL\",\n            'openid' => Schema::TYPE_STRING . \" NOT NULL\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type', $tableName, 'type');\n        $this->createIndex('user_id', $tableName, 'user_id');\n    }\n\n\n    public function down()\n    {\n        echo \"m150104_091352_init_user cannot be reverted.\\n\";\n        $this->dropColumn('{{%user}}', 'avatar');\n        $this->dropTable('{{%user_meta}}');\n        $this->dropTable('{{%user_auth}}');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150115_081356_create_user_info.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150115_081356_create_user_info extends Migration\n{\n    public function up()\n    {\n    \t$this->createTable('{{%user_info}}', [\n    \t    'id' => Schema::TYPE_PK,\n    \t    'user_id' => Schema::TYPE_INTEGER . ' UNSIGNED NOT NULL',\n    \t    'info' => Schema::TYPE_STRING . ' DEFAULT NULL COMMENT \"会员简介\"',\n    \t    'login_count' => Schema::TYPE_INTEGER . ' DEFAULT 1 COMMENT \"登录次数\"',\n    \t    'prev_login_time' => Schema::TYPE_INTEGER . ' UNSIGNED NOT NULL COMMENT \"上次登录时间\"',\n    \t    'prev_login_ip' => Schema::TYPE_STRING . '(32) NOT NULL COMMENT \"上次登录IP\"',\n    \t    'last_login_time' => Schema::TYPE_INTEGER . ' UNSIGNED NOT NULL COMMENT \"最后登录时间\"',\n    \t    'last_login_ip' => Schema::TYPE_STRING . '(32) NOT NULL COMMENT \"最后登录IP\"',\n    \t    'created_at' => Schema::TYPE_INTEGER . ' UNSIGNED NOT NULL',\n    \t    'updated_at' => Schema::TYPE_INTEGER . ' UNSIGNED NOT NULL',\n    \t], $this->tableOptions);\n    }\n\n    public function down()\n    {\n        echo \"m150115_081356_create_user_info cannot be reverted.\\n\";\n        $this->dropTable('{{%user_info}}');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150201_142415_update_user.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150201_142415_update_user extends Migration\n{\n    public function up()\n    {\n    \t$this->addColumn('{{%user_info}}', 'location' , Schema::TYPE_STRING . '(10) DEFAULT NULL COMMENT \"城市\" AFTER `info`');\n    \t$this->addColumn('{{%user_info}}', 'company' , Schema::TYPE_STRING . '(40) DEFAULT NULL COMMENT \"公司\" AFTER `info`');\n    \t$this->addColumn('{{%user_info}}', 'website' , Schema::TYPE_STRING . '(100) DEFAULT NULL COMMENT \"个人主页\" AFTER `info`');\n    \t$this->addColumn('{{%user_info}}', 'github' , Schema::TYPE_STRING . '(100) DEFAULT NULL COMMENT \"GitHub 帐号\" AFTER `info`');\n    \t$this->addColumn('{{%user}}', 'tagline' , Schema::TYPE_STRING . '(40) DEFAULT NULL COMMENT \"一句话介绍\" AFTER `email`');\n    }\n\n    public function down()\n    {\n        echo \"m150201_142415_update_user cannot be reverted.\\n\";\n        $this->dropColumn('{{%user_info}}', 'location');\n        $this->dropColumn('{{%user_info}}', 'company');\n        $this->dropColumn('{{%user_info}}', 'website');\n        $this->dropColumn('{{%user_info}}', 'github');\n        $this->dropColumn('{{%user}}', 'tagline');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150205_085033_update_post_comment.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150205_085033_update_post_comment extends Migration\n{\n    public function up()\n    {\n    \t$this->addColumn('{{%post_comment}}', 'updated_at', Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间'\");\n    \t$this->addColumn('{{%post_comment}}', 'like_count', Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '喜欢数' AFTER `user_id`\");\n    }\n\n    public function down()\n    {\n        echo \"m150205_085033_update_post_comment cannot be reverted.\\n\";\n        $this->dropColumn('{{%post_comment}}', 'updated_at');\n        $this->dropColumn('{{%post_comment}}', 'like_count');\n        return false;\n    }\n}"
  },
  {
    "path": "console/migrations/m150209_015931_setting_init.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150209_015931_setting_init extends Migration\n{\n    public function up()\n    {\n    \t$this->execute($this->delSetting());\n    \t$tableName = '{{%setting}}';\n    \t$this->createTable($tableName, [\n\t        'id' => Schema::TYPE_PK,\n\t        'parent_id' => Schema::TYPE_INTEGER . ' NOT NULL DEFAULT 0',\n\t        'code' => Schema::TYPE_STRING . '(32) NOT NULL',\n\t        'type' => Schema::TYPE_STRING . '(32) NOT NULL',\n\t        'store_range' => Schema::TYPE_STRING . '(255)',\n\t        'store_dir' => Schema::TYPE_STRING . '(255)',\n\t        'value' => Schema::TYPE_TEXT . '',\n\t        'sort_order' => Schema::TYPE_INTEGER . ' NOT NULL DEFAULT 50',\n\t    ], $this->tableOptions);\n\n    \t// Indexes\n    \t$this->createIndex('parent_id', $tableName, 'parent_id');\n    \t$this->createIndex('code', $tableName, 'code');\n    \t$this->createIndex('sort_order', $tableName, 'sort_order');\n\n    \t// Add default setting\n    \t$this->execute($this->getSettingSql());\n    }\n\n    /**\n     * @return string SQL to insert first user\n     */\n    private function getSettingSql()\n    {\n        return \"INSERT INTO {{%setting}} (`id`, `parent_id`, `code`, `type`, `store_range`, `store_dir`, `value`, `sort_order`) VALUES\n                (11, 0, 'info', 'group', '', '', '', '50'),\n                (21, 0, 'basic', 'group', '', '', '', '50'),\n                (31, 0, 'smtp', 'group', '', '', '', '50'),\n                (41, 0, 'github', 'group', '', '', '', '50'),\n                (51, 0, 'google', 'group', '', '', '', '50'),\n                (1111, 11, 'siteName', 'text', '', '', 'Your Site', '50'),\n                (1112, 11, 'siteTitle', 'text', '', '', 'Your Site Title', '50'),\n                (1113, 11, 'siteKeyword', 'text', '', '', 'Your Site Keyword', '50'),\n                (2111, 21, 'timezone', 'select', '-12,-11,-10,-9,-8,-7,-6,-5,-4,-3.5,-3,-2,-1,0,1,2,3,3.5,4,4.5,5,5.5,5.75,6,6.5,7,8,9,9.5,10,11,12', '', '8', '50'),\n                (2112, 21, 'commentCheck', 'select', '0,1', '', '1', '50'),\n                (3111, 31, 'smtpHost', 'text', '', '', 'localhost', '50'),\n                (3112, 31, 'smtpPort', 'text', '', '', '', '50'),\n                (3113, 31, 'smtpUser', 'text', '', '', '', '50'),\n                (3114, 31, 'smtpPassword', 'password', '', '', '', '50'),\n                (3115, 31, 'smtpMail', 'text', '', '', '', '50'),\n                (4111, 41, 'githubLogin', 'select', '0,1', '', '1', '50'),\n                (4112, 41, 'githubClientId', 'text', '', '', '', '50'),\n                (4113, 41, 'githubClientSecret', 'text', '', '', '', '50'),\n                (5111, 51, 'googleLogin', 'select', '0,1', '', '1', '50'),\n                (5112, 51, 'googleClientId', 'text', '', '', '', '50'),\n                (5113, 51, 'googleClientSecret', 'text', '', '', '', '50')\n                \";\n    }\n\n    private function delSetting()\n    {\n    \treturn \"DROP TABLE IF EXISTS {{%setting}};\";\n    }\n\n    public function down()\n    {\n        echo \"m150209_015931_setting_init cannot be reverted.\\n\";\n        $this->dropTable('{{%setting}}');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150209_090406_create_user_account.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150209_090406_create_user_account extends Migration\n{\n    public function up()\n    {\n    \t$this->execute($this->delTable());\n    \t// 会员第三方登录账号表\n    \t$tableName = '{{%user_account}}';\n    \t$this->createTable($tableName, [\n    \t    'id' => Schema::TYPE_PK,\n    \t    'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '用户ID'\",\n    \t    'provider' => Schema::TYPE_STRING . \"(100) NOT NULL DEFAULT '' COMMENT '授权提供商'\",\n    \t    'client_id' => Schema::TYPE_STRING . \" NOT NULL\",\n    \t    'data' => Schema::TYPE_TEXT . \" NOT NULL\",\n    \t    'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n    \t], $this->tableOptions);\n    \t$this->createIndex('client_id', $tableName, 'client_id');\n    \t$this->createIndex('user_id', $tableName, 'user_id');\n    }\n\n    private function delTable()\n    {\n    \treturn \"DROP TABLE IF EXISTS {{%user_auth}};\";\n    }\n\n    public function down()\n    {\n        echo \"m150209_090406_create_user_account cannot be reverted.\\n\";\n        $this->dropTable('{{%user_account}}');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150211_070335_update_user_info.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150211_070335_update_user_info extends Migration\n{\n    public function up()\n    {\n    \t$this->addColumn('{{%user_info}}', 'like_count' , Schema::TYPE_INTEGER . ' DEFAULT 0 COMMENT \"被赞次数\" AFTER `location`');\n    \t$this->addColumn('{{%user_info}}', 'thanks_count' , Schema::TYPE_INTEGER . ' DEFAULT 0 COMMENT \"被感谢次数\" AFTER `location`');\n    \t$this->addColumn('{{%user_info}}', 'post_count' , Schema::TYPE_INTEGER . ' DEFAULT 0 COMMENT \"发布文章数\" AFTER `location`');\n    \t$this->addColumn('{{%user_info}}', 'comment_count' , Schema::TYPE_INTEGER . ' DEFAULT 0 COMMENT \"发布评论数\" AFTER `location`');\n    \t$this->addColumn('{{%user_info}}', 'view_count' , Schema::TYPE_INTEGER . ' DEFAULT 0 COMMENT \"个人主页浏览次数\" AFTER `location`');\n    }\n\n    public function down()\n    {\n        echo \"m150211_070335_update_user_info cannot be reverted.\\n\";\n        $this->dropColumn('{{%user_info}}', 'like_count');\n        $this->dropColumn('{{%user_info}}', 'thanks_count');\n        $this->dropColumn('{{%user_info}}', 'post_count');\n        $this->dropColumn('{{%user_info}}', 'comment_count');\n        $this->dropColumn('{{%user_info}}', 'view_count');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150212_030127_update_user_info_and_post_meta.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150212_030127_update_user_info_and_post_meta extends Migration\n{\n    public function up()\n    {\n    \t$this->addColumn('{{%user_info}}', 'hate_count' , Schema::TYPE_INTEGER . ' DEFAULT 0 COMMENT \"喝倒彩次数\" AFTER `like_count`');\n    }\n\n    public function down()\n    {\n        echo \"m150212_030127_update_user_info_and_post_meta cannot be reverted.\\n\";\n        $this->dropColumn('{{%user_info}}', 'hate_count');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150212_132400_create_topics_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150212_132400_create_topics_table extends Migration\n{\n    public function up()\n    {\n    \t$this->addColumn('{{%post}}', 'type' , Schema::TYPE_STRING . '(32) DEFAULT \"blog\" COMMENT \"内容类型\" AFTER `id`');\n    \t// 修改字段\n    \t$this->alterColumn('{{%post}}', 'tags' , Schema::TYPE_STRING . \" DEFAULT NULL COMMENT '标签 用英文逗号隔开'\");\n    \t$this->alterColumn('{{%post}}', 'post_meta_id' , Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '版块ID'\");\n    \t$this->createIndex('type', '{{%post}}', 'type');\n    }\n\n    public function down()\n    {\n        echo \"m150212_132400_create_topics_table cannot be reverted.\\n\";\n        $this->dropColumn('{{%post}}', 'type');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150214_070754_update_post_meta.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150214_070754_update_post_meta extends Migration\n{\n    public function up()\n    {\n    \t$this->addColumn('{{%post_meta}}', 'alias' , Schema::TYPE_STRING . \"(32) DEFAULT NULL COMMENT '变量（别名）' AFTER `name`\");\n        $this->createIndex('alias', '{{%post_meta}}', 'alias');\n    }\n\n    public function down()\n    {\n        echo \"m150214_070754_update_post_meta cannot be reverted.\\n\";\n        $this->dropColumn('{{%post_meta}}', 'alias');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150412_034147_update_site_setting.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150412_034147_update_site_setting extends Migration\n{\n    public function up()\n    {\n    \t$this->execute($this->delSettingSql());\n    \t$this->execute($this->updateSettingSql());\n    \t$this->execute($this->getSettingSql());\n    }\n\n    /**\n     * @return string SQL to insert first user\n     */\n    private function getSettingSql()\n    {\n        return \"INSERT INTO {{%setting}} (`id`, `parent_id`, `code`, `type`, `store_range`, `store_dir`, `value`, `sort_order`) VALUES\n            (1114, 11, 'siteAnalytics', 'text', '', '', 'Your Site Analytics', '50'),\n            (4114, 41, 'googleLogin', 'select', '0,1', '', '1', '50'),\n            (4115, 41, 'googleClientId', 'text', '', '', '', '50'),\n            (4116, 41, 'googleClientSecret', 'text', '', '', '', '50'),\n            (4117, 41, 'weiboLogin', 'select', '0,1', '', '1', '50'),\n            (4118, 41, 'weiboClientId', 'text', '', '', '', '50'),\n            (4119, 41, 'weiboClientSecret', 'text', '', '', '', '50'),\n            (4120, 41, 'qqLogin', 'select', '0,1', '', '1', '50'),\n            (4121, 41, 'qqClientId', 'text', '', '', '', '50'),\n            (4122, 41, 'qqClientSecret', 'text', '', '', '', '50')\n            \";\n    }\n\n    private function updateSettingSql()\n    {\n        return \"UPDATE {{%setting}} SET `code` = 'account' WHERE `id` = 41\";\n    }\n\n    private function delSettingSql()\n    {\n        return \"DELETE FROM {{%setting}} WHERE `id` IN (\n\t\t\t\t51, 5111, 5112, 5113\n        \t)\";\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150416_134819_create_notification_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150416_134819_create_notification_table extends Migration\n{\n    public function up()\n    {\n        $tableName = '{{%notification}}';\n        $this->createTable($tableName, [\n            'id' => Schema::TYPE_PK,\n            'from_user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '通知来源用户ID'\",\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '用户ID'\",\n            'post_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL COMMENT '文章ID'\",\n            'comment_id' => Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '文章评论ID'\",\n            'type' => Schema::TYPE_STRING . \" NOT NULL COMMENT '通知类型'\",\n            'data' => Schema::TYPE_TEXT . \" NOT NULL COMMENT '通知内容'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type', $tableName, 'type');\n        $this->createIndex('post_id', $tableName, 'post_id');\n        $this->createIndex('user_id', $tableName, 'user_id');\n        $this->addColumn('{{%user}}', 'notification_count' , Schema::TYPE_INTEGER . ' UNSIGNED DEFAULT 0 COMMENT \"通知条数\" AFTER `tagline`');\n    }\n\n    public function down()\n    {\n        echo \"m150416_134819_create_notifications_table cannot be reverted.\\n\";\n        $this->dropTable('{{%notification}}');\n        $this->dropColumn('{{%user}}', 'notification_count');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150420_060807_update_post_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150420_060807_update_post_table extends Migration\n{\n    public function up()\n    {\n        $this->addColumn('{{%post}}', 'follow_count' , Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '讨厌数' AFTER `view_count`\");\n    }\n\n    public function down()\n    {\n        echo \"m150420_060807_update_post_table cannot be reverted.\\n\";\n        $this->dropColumn('{{%post}}', 'follow_count');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150424_025409_update_table_engine.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150424_025409_update_table_engine extends Migration\n{\n    public function safeUp()\n    {\n        $this->changeEngine('MyISAM', 'InnoDB');\n    }\n\n    public function safeDown()\n    {\n        echo \"m150424_025409_update_table_engine cannot be reverted.\\n\";\n        $this->changeEngine('InnoDB', 'MyISAM');\n    }\n\n    protected function changeEngine($from, $to)\n    {\n        $table = [\n            '{{%notification}}',\n            '{{%post}}',\n            '{{%post_meta}}',\n            //'{{%post_tag}}',\n            //'{{%setting}}',\n            '{{%user}}',\n            '{{%user_info}}',\n            '{{%user_meta}}',\n        ];\n        foreach ($table as $key => $value) {\n            $this->execute(\"ALTER TABLE $value ENGINE = {$to};\");\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "console/migrations/m150424_031429_update_notification_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150424_031429_update_notification_table extends Migration\n{\n    public function safeUp()\n    {\n        $this->addColumn('{{%notification}}', 'status' , Schema::TYPE_BOOLEAN . \" UNSIGNED NOT NULL DEFAULT '1' COMMENT '状态 1显示 0不显示' AFTER `data`\");\n    }\n\n    public function safeDown()\n    {\n        echo \"m150424_031429_update_notification_table cannot be reverted.\\n\";\n        $this->dropColumn('{{%notification}}', 'status');\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "console/migrations/m150424_100155_update_post_meta_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150424_100155_update_post_meta_table extends Migration\n{\n\n    public function safeUp()\n    {\n        $this->addColumn('{{%post_meta}}', 'parent', Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '父级ID' AFTER `name`\");\n    }\n\n    public function safeDown()\n    {\n        echo \"m150424_100155_update_post_meta_table cannot be reverted.\\n\";\n        $this->dropColumn('{{%post_meta}}', 'parent');\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "console/migrations/m150425_031844_create_right_link.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\n\nclass m150425_031844_create_right_link extends \\common\\components\\db\\Migration\n{\n    public function up()\n    {\n        $this->execute('DROP TABLE IF EXISTS {{%rightlink}}');\n        $table = '{{%right_link}}';\n        $this->createTable($table, [\n            'id' => Schema::TYPE_PK,\n            'title' => Schema::TYPE_STRING . ' NOT NULL COMMENT \"标题\"',\n            'url' => Schema::TYPE_STRING . '(225) ',\n            'image' => Schema::TYPE_STRING . '(255) COMMENT \"图片链接\"',\n            'content' => Schema::TYPE_STRING . '(255) COMMENT \"内容\"',\n            'type' => Schema::TYPE_INTEGER . '(5) COMMENT \"展示类别\"',\n            'created_user' => Schema::TYPE_STRING . '(32) NOT NULL COMMENT \"创建人\"',\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type_index', $table, 'type');\n    }\n\n    public function down()\n    {\n        echo \"m150425_031844_create_rightLink cannot be reverted.\\n\";\n        $this->dropTable('{{%right_link}}');\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "console/migrations/m150626_073539_create_nav.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150626_073539_create_nav extends Migration\n{\n    public function up()\n    {\n        $this->execute('DROP TABLE IF EXISTS {{%nav}}');\n        $table = '{{%nav}}';\n        $this->createTable($table, [\n            'id' => Schema::TYPE_PK,\n            'name' => Schema::TYPE_STRING . ' NOT NULL COMMENT \"名称\"',\n            'alias' => Schema::TYPE_STRING .' NOT NULL COMMENT \"变量（别名）\"',\n            'order' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '99' COMMENT '项目排序'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间'\",\n        ]);\n    }\n\n    public function down()\n    {\n        echo \"m150626_073539_create_nav cannot be reverted.\\n\";\n        $this->dropTable('{{%nav}}');\n        return false;\n    }\n    \n    /*\n    // Use safeUp/safeDown to run migration code within a transaction\n    public function safeUp()\n    {\n    }\n    \n    public function safeDown()\n    {\n    }\n    */\n}\n"
  },
  {
    "path": "console/migrations/m150626_073559_create_nav_url.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150626_073559_create_nav_url extends Migration\n{\n    public function up()\n    {\n        $this->execute('DROP TABLE IF EXISTS {{%nav_url}}');\n        $table = '{{%nav_url}}';\n        $this->createTable($table, [\n            'id' => Schema::TYPE_PK,\n            'nav_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '导航分类ID'\",\n            'title' => Schema::TYPE_STRING . ' NOT NULL COMMENT \"标题\"',\n            'url' => Schema::TYPE_STRING . '(225) NOT NULL COMMENT \"链接\"',\n            'description' => Schema::TYPE_STRING . '(255) COMMENT \"描述\"',\n            'order' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '99' COMMENT '项目排序'\",\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '用户ID'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '修改时间'\",\n        ]);\n    }\n\n    public function down()\n    {\n        echo \"m150626_073559_create_nav_url cannot be reverted.\\n\";\n        $this->dropTable('{{%nav_url}}');\n        return false;\n    }\n    \n    /*\n    // Use safeUp/safeDown to run migration code within a transaction\n    public function safeUp()\n    {\n    }\n    \n    public function safeDown()\n    {\n    }\n    */\n}\n"
  },
  {
    "path": "console/migrations/m150702_130239_create_session_init.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150702_130239_create_session_init extends Migration\n{\n    public $tableName = '{{%session}}';\n\n    public function up()\n    {\n        $this->createTable($this->tableName, [\n            'id' => \"varchar(40) NOT NULL\",\n            'expire' => \"int(11)\",\n            'data' => \"blob\",\n        ]);\n        $this->addPrimaryKey('idx', $this->tableName, 'id');\n        $this->createIndex('idx_expire', $this->tableName, 'expire');\n        $this->addColumn('{{%user_info}}', 'session_id', Schema::TYPE_STRING . \"(100) DEFAULT NULL AFTER `last_login_ip`\");\n    }\n\n    public function down()\n    {\n        echo \"m150702_130239_create_session_init cannot be reverted.\\n\";\n        $this->dropTable($this->tableName);\n        $this->dropColumn('{{%user_info}}', 'session_id');\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "console/migrations/m150805_085832_create_search_log_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse common\\components\\db\\Migration;\n\nclass m150805_085832_create_search_log_table extends Migration\n{\n    public $tableName = '{{%search_log}}';\n\n    public function up()\n    {\n        $this->createTable($this->tableName, [\n            'id' => Schema::TYPE_PK,\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '用户ID'\",\n            'keyword' => Schema::TYPE_STRING . \" NOT NULL DEFAULT '' COMMENT '搜索关键词'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('keyword', $this->tableName, 'keyword');\n        $this->createIndex('user_id', $this->tableName, 'user_id');\n    }\n\n    public function down()\n    {\n        echo \"m150805_085832_create_search_log_table cannot be reverted.\\n\";\n        $this->dropTable($this->tableName);\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150808_025734_update_table_character.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150808_025734_update_table_character extends Migration\n{\n    public function safeUp()\n    {\n        $this->changeCharacter('utf8mb4', 'utf8mb4_general_ci');\n    }\n\n    public function safeDown()\n    {\n        echo \"m150720_031448_update_table_character cannot be reverted.\\n\";\n        $this->changeCharacter('utf8', 'utf8_general_ci');\n    }\n\n    protected function changeCharacter($toA, $toB)\n    {\n        $this->execute(\"ALTER TABLE {{%post_comment}} MODIFY COLUMN `comment` text CHARACTER SET {$toA} COLLATE {$toB};\");\n        $this->execute(\"ALTER TABLE {{%post}} MODIFY COLUMN `content` text CHARACTER SET {$toA} COLLATE {$toB};\");\n        $this->execute(\"ALTER TABLE {{%notification}} MODIFY COLUMN `data` text CHARACTER SET {$toA} COLLATE {$toB};\");\n    }\n}\n"
  },
  {
    "path": "console/migrations/m150829_091943_update_post_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m150829_091943_update_post_table extends Migration\n{\n    public function up()\n    {\n        $this->addColumn('{{%post}}', 'last_comment_username' , Schema::TYPE_STRING . '(20) DEFAULT NULL COMMENT \"最后评论用户\" AFTER `tags`');\n        $this->addColumn('{{%post}}', 'last_comment_time' , Schema::TYPE_INTEGER . ' DEFAULT NULL COMMENT \"最后评论用户\" AFTER `tags`');\n    }\n\n    public function down()\n    {\n        echo \"m150829_091943_update_post_table cannot be reverted.\\n\";\n        $this->dropColumn('{{%post}}', 'last_comment_time');\n        $this->dropColumn('{{%post}}', 'last_comment_username');\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m160320_093621_create_merit_table.php",
    "content": "<?php\n\nuse yii\\db\\Schema;\nuse yii\\db\\Migration;\n\nclass m160320_093621_create_merit_table extends Migration\n{\n    /**\n     * 创建表选项\n     * @var string\n     */\n    public $tableOptions = null;\n\n    /**\n     * 是否事务性存储表, 则创建为事务性表. 默认不使用\n     * @var bool\n     */\n    public $useTransaction = true;\n\n    public function init()\n    {\n        parent::init();\n\n        if ($this->db->driverName === 'mysql') { //Mysql 表选项\n            $engine = $this->useTransaction ? 'InnoDB' : 'MyISAM';\n            $this->tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=' . $engine;\n        }\n    }\n\n    public function up()\n    {\n        $this->execute($this->delMeritTable());\n        $this->createTable('{{%merit_template}}', [\n            'id' => Schema::TYPE_PK,\n            'type' => Schema::TYPE_INTEGER . \"(2) DEFAULT 1 COMMENT '类型 1:积分 2:声望 3:徽章'\",\n            'title' => Schema::TYPE_STRING . \" NOT NULL COMMENT '标题'\",\n            'unique_id' => Schema::TYPE_STRING . \" NOT NULL COMMENT 'action uniqueId'\",\n            'method' => Schema::TYPE_INTEGER . \"(2) DEFAULT 2 COMMENT '请求方式 1 get 2 post'\",\n            'event' => Schema::TYPE_INTEGER . \"(2) DEFAULT 0 COMMENT '事件 0:不绑定'\",\n            'action_type' => Schema::TYPE_INTEGER . \"(2) DEFAULT 2 COMMENT '操作类型 1减去 2新增'\",\n            'rule_key' => Schema::TYPE_INTEGER . \"(2) DEFAULT 0 COMMENT '规则类型 0:不限制 1:按天限制 2:按次限制'\",\n            'rule_value' => Schema::TYPE_INTEGER . \" DEFAULT 0 COMMENT '规则值'\",\n            'increment' => Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '变化值'\",\n            'status' => Schema::TYPE_BOOLEAN . \" DEFAULT 1 COMMENT '状态 0暂停 1开启'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '更新时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type', '{{%merit_template}}', 'type');\n        $this->createIndex('unique_id', '{{%merit_template}}', 'unique_id');\n\n        $this->createTable('{{%merit}}', [\n            'id' => Schema::TYPE_PK,\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '用户ID'\",\n            'username' => Schema::TYPE_STRING . \"(20) DEFAULT NULL COMMENT '用户名'\",\n            'type' => Schema::TYPE_INTEGER . \"(2) DEFAULT 1 COMMENT '类型 1:积分 2:声望 3:徽章'\",\n            'merit' => Schema::TYPE_INTEGER . \" DEFAULT NULL COMMENT '总值'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n            'updated_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '更新时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type', '{{%merit}}', 'type');\n        $this->createIndex('user_id', '{{%merit}}', 'user_id');\n\n        $this->createTable('{{%merit_log}}', [\n            'id' => Schema::TYPE_PK,\n            'user_id' => Schema::TYPE_INTEGER . \" UNSIGNED NULL NULL COMMENT '用户ID'\",\n            'username' => Schema::TYPE_STRING . \"(20) DEFAULT NULL COMMENT '用户名'\",\n            'merit_template_id' => Schema::TYPE_INTEGER . \" UNSIGNED NULL NULL COMMENT '模板ID'\",\n            'type' => Schema::TYPE_INTEGER . \"(2) DEFAULT 1 COMMENT '类型 1:积分 2:声望 3:徽章'\",\n            'description' => Schema::TYPE_STRING . \" NOT NULL COMMENT '描述'\",\n            'action_type' => Schema::TYPE_INTEGER . \"(2) DEFAULT 2 COMMENT '操作类型 1减去 2新增'\",\n            'increment' => Schema::TYPE_INTEGER . \" UNSIGNED DEFAULT NULL COMMENT '变化值'\",\n            'created_at' => Schema::TYPE_INTEGER . \" UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间'\",\n        ], $this->tableOptions);\n        $this->createIndex('type', '{{%merit_log}}', 'type');\n        $this->createIndex('user_id', '{{%merit_log}}', 'user_id');\n        $this->createIndex('merit_template_id', '{{%merit_log}}', 'merit_template_id');\n    }\n\n    public function down()\n    {\n        echo \"m150807_082458_create_merit_table cannot be reverted.\\n\";\n        $this->dropTable('{{%merit_template}}');\n        $this->dropTable('{{%merit}}');\n        $this->dropTable('{{%merit_log}}');\n        return false;\n    }\n\n    /**\n     * @return string\n     */\n    private function delMeritTable()\n    {\n        return 'DROP TABLE IF EXISTS {{%merit_template}};\n                DROP TABLE IF EXISTS {{%merit}};\n                DROP TABLE IF EXISTS {{%merit_log}};\n              ';\n    }\n}\n"
  },
  {
    "path": "console/migrations/m160321_132724_add_donate_table.php",
    "content": "<?php\n\nuse common\\components\\db\\Migration;\n\nclass m160321_132724_add_donate_table extends Migration\n{\n    public $tableName = '{{%donate}}';\n\n    public function up()\n    {\n        $this->createTable($this->tableName, [\n            'id' => $this->primaryKey(),\n            'user_id' => $this->integer()->notNull(),\n            'status' => $this->boolean()->defaultValue(1),\n            'description' => $this->string(),\n            'qr_code' => $this->string(),\n            'created_at' => $this->integer(),\n            'updated_at' => $this->integer(),\n        ], $this->tableOptions);\n        $this->createIndex('user_id', $this->tableName, 'user_id');\n    }\n\n    public function down()\n    {\n        echo \"m160321_132724_add_donate_table cannot be reverted.\\n\";\n        $this->dropTable($this->tableName);\n        return false;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m160719_093527_modify_user.php",
    "content": "<?php\n\nuse yii\\db\\Migration;\n\nclass m160719_093527_modify_user extends Migration\n{\n    public $userTable = '{{%user}}';\n\n    public function up()\n    {\n        $this->createIndex('idx_username', $this->userTable, 'username', true);\n    }\n\n    public function down()\n    {\n        $this->dropIndex('idx_username', $this->userTable);\n    }\n\n    /*\n    // Use safeUp/safeDown to run migration code within a transaction\n    public function safeUp()\n    {\n    }\n\n    public function safeDown()\n    {\n    }\n    */\n}\n"
  },
  {
    "path": "console/migrations/m190624_022722_create_spam_table.php",
    "content": "<?php\n\nuse yii\\db\\Migration;\nuse yiier\\antiSpam\\models\\Spam;\n\n/**\n * Handles the creation of table `{{%spam}}`.\n */\nclass m190624_022722_create_spam_table extends Migration\n{\n    /**\n     * 创建表选项\n     * @var string\n     */\n    public $tableOptions = null;\n\n    /**\n     * 是否事务性存储表, 则创建为事务性表. 默认不使用\n     * @var bool\n     */\n    public $useTransaction = false;\n\n    public function init()\n    {\n        parent::init();\n        if ($this->db->driverName === 'mysql') {\n            //Mysql 表选项\n            $engine = $this->useTransaction ? 'InnoDB' : 'MyISAM';\n            $this->tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=' . $engine;\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function safeUp()\n    {\n        $this->createTable('{{%spam}}', [\n            'id' => $this->primaryKey(),\n            'status' => $this->tinyInteger(1)->defaultValue(1)->comment('0 or 1'),\n            'content' => $this->text()->notNull(),\n            'type' => $this->string(20)->defaultValue('contains')->comment('contains or similar'),\n            'for' => $this->string(20)->defaultValue('all'),\n        ], $this->tableOptions);\n\n        $this->createIndex('fk_status_for', '{{%spam}}', ['status', 'for']);\n        self::initData();\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function safeDown()\n    {\n        $this->dropTable('{{%spam}}');\n    }\n\n\n    public static function initData()\n    {\n        Spam::create(Spam::TYPE_CONTAINS, '网{3}赌');\n        Spam::create(Spam::TYPE_CONTAINS, '找小姐');\n        Spam::create(Spam::TYPE_SIMILAR, '网赌平台冻账号说我违规套利不给出款该怎么办？');\n    }\n}\n"
  },
  {
    "path": "console/migrations/m190908_053628_init_admin.php",
    "content": "<?php\n\nuse yii\\helpers\\Console;\nuse yii\\db\\Migration;\n\nclass m190908_053628_init_admin extends Migration\n{\n    public function up()\n    {\n        $this->createFounder();\n    }\n\n    public function down()\n    {\n        echo \"m190908_053628_init_admin cannot be reverted.\\n\";\n\n        return false;\n    }\n\n    /**\n     * 创建创始人数据\n     */\n    public function createFounder()\n    {\n        Console::output(\"\\n请先创建创始人账户:   \");\n\n        $user = $this->saveFounderData(new \\frontend\\models\\SignupForm());\n\n        $user ? $user->id : 1; // 用户创建成功则指定用户id,否则指定id为1的用户为创始人.\n\n        Console::output(\"创始人创建\" . ($user ? '成功' : \"失败,请手动创建创始人用户\\n\"));\n    }\n\n    /**\n     * 用户创建交互\n     * @param $_model\n     * @return mixed\n     */\n    private function saveFounderData($_model)\n    {\n        /** @var \\frontend\\models\\SignupForm $model */\n        $model = clone $_model;\n        $model->username = Console::prompt('请输入创始人用户名', ['default' => 'admin']);\n        $model->email = Console::prompt('请输入创始人邮箱', ['default' => 'admin@admin.com']);\n        $model->password = Console::prompt('请输入创始人密码', ['default' => '123456']);\n        $model->role = \\common\\models\\User::ROLE_SUPER_ADMIN;\n\n        if (!($user = $model->signup())) {\n            Console::output(Console::ansiFormat(\"\\n输入数据验证错误:\", [Console::FG_RED]));\n            foreach ($model->getErrors() as $k => $v) {\n                Console::output(Console::ansiFormat(implode(\"\\n\", $v), [Console::FG_RED]));\n            }\n            if (Console::confirm(\"\\n是否重新创建创始人账户:\")) {\n                $user = $this->saveFounderData($_model);\n            }\n        }\n        return $user;\n    }\n}\n"
  },
  {
    "path": "console/migrations/m190908_055507_init_data.php",
    "content": "<?php\n\nuse yii\\db\\Migration;\nuse yii\\helpers\\Console;\nuse frontend\\modules\\topic\\models\\Topic;\nuse common\\models\\PostComment;\nuse common\\models\\PostMeta;\nuse common\\models\\User;\nuse common\\models\\UserInfo;\nuse yii\\db\\Exception;\n\nclass m190908_055507_init_data extends Migration\n{\n    public function up()\n    {\n        if (Console::confirm('是否生成测试问题数据?', true)) {\n            $this->generateFakeData(rand(20, 100));\n        }\n    }\n\n    public function down()\n    {\n        echo \"m190908_055507_init_data cannot be reverted.\\n\";\n\n        return false;\n    }\n\n\n    public function generateFakeData($num)\n    {\n        Console::startProgress(0, 100);\n        $topic = new Topic();\n        $comment = new PostComment();\n        $node = new PostMeta();\n\n        $faker = Faker\\Factory::create('zh_CN');\n        $nodeData = [\n            ['name' => '分享', 'alias' => '', 'parent' => 0],\n            ['name' => '招聘', 'alias' => 'jobs', 'parent' => 1],\n            ['name' => '瞎扯淡', 'alias' => 'booshit', 'parent' => 1],\n            ['name' => '健康', 'alias' => 'health', 'parent' => 1],\n            ['name' => '创业', 'alias' => 'startup', 'parent' => 1],\n        ];\n        $transaction = Yii::$app->db->beginTransaction();\n        try {\n            for ($j = 0; $j < count($nodeData); $j++) {\n                $_node = clone $node;\n                $_node->setAttributes($nodeData[$j] + ['type' => 'topic_category']);\n                $_node->save();\n            }\n\n            $this->execute(\"INSERT INTO {{%merit_template}} (`id`, `type`, `title`, `unique_id`, `method`, `event`, `action_type`, `rule_key`, `rule_value`, `increment`, `status`, `created_at`, `updated_at`) VALUES\n(1, 1, '登录', 'site/login', 2, 0, 2, 1, 1, 2, 1, 1458657160, 1458823425),\n(2, 1, '发帖', 'topic/default/create', 2, 0, 2, 0, NULL, 6, 1, 1458657218, 1458657218),\n(3, 1, '回复', 'topic/comment/create', 2, 0, 2, 0, NULL, 4, 1, 1458657251, 1458657251),\n(4, 1, '发动弹', 'tweet/default/create', 2, 0, 2, 0, NULL, 4, 1, 1458657296, 1468647701);\n\");\n            /** @var User $user */\n            $user = User::find()->where(['role' => User::ROLE_SUPER_ADMIN])->one();\n            Yii::$app->user->setIdentity($user);\n            for ($i = 1; $i <= $num; $i++) {\n                $_topic = clone $topic;\n                $_topic->setAttributes([\n                    'type' => Topic::TYPE,\n                    'title' => $faker->text(rand(10, 50)),\n                    'post_meta_id' => rand(2, 4),\n                    'status' => rand(1, 2),\n                    'content' => $faker->text(rand(100, 2000)),\n                    'user_id' => 1\n                ]);\n                if (!$_topic->save()) {\n                    throw new Exception(array_values($_topic->getFirstErrors())[0]);\n                }\n\n                for ($_i = 1; $_i <= rand(1, 20); $_i++) {\n                    $_comment = clone $comment;\n                    $_comment->setAttributes([\n                        'comment' => $faker->text(rand(100, 2000)),\n                        'post_id' => $_topic->id,\n                        'ip' => '127.0.0.1',\n                        'user_id' => 1\n                    ]);\n                    if (!$_comment->save()) {\n                        throw new Exception(array_values($_comment->getFirstErrors())[0]);\n                    }\n\n                    // 更新回复时间\n                    $_topic->lastCommentToUpdate($user['username']);\n                    // 评论计数器\n                    Topic::updateAllCounters(['comment_count' => 1], ['id' => $_topic->id]);\n                    // 更新个人总统计\n                    UserInfo::updateAllCounters(['comment_count' => 1], ['user_id' => $_topic->user_id]);\n                }\n                Console::updateProgress($i / $num * 100, 100);\n            }\n            $transaction->commit();\n        } catch (\\Exception $e) {\n            $transaction->rollBack();\n            throw $e;\n        }\n        Console::endProgress();\n    }\n}\n"
  },
  {
    "path": "console/models/.gitkeep",
    "content": "*\n"
  },
  {
    "path": "console/runtime/.gitignore",
    "content": "*\n!.gitignore"
  },
  {
    "path": "doc/README.md",
    "content": "## 本文件夹是功能详细设计文档\r\n\r\n本文档主要由 @forecho 设计。"
  },
  {
    "path": "docker-files/docker-compose-example.yml",
    "content": "mysql:\n  image: mysql\n  environment:\n    - MYSQL_DATABASE=getyii\n    - MYSQL_ROOT_PASSWORD=getyii.com\n  ports:\n    - 3306:3306\n\nweb:\n  build: .\n  links:\n    - mysql:mysql\n  ports:\n    - 80:80\n  environment:\n    - MYSQL_INSTANCE_NAME=getyii\n    - MYSQL_PASSWORD=getyii.com\n    - APP_ENV=Production\n  volumes:\n    - ./vendor:/app/vendor:rw\n    - ~/.composer/cache:/root/.composer/cache:rw\n    # - .:/app:rw # you should uncomment this line if you want to develop the app.\n"
  },
  {
    "path": "docker-files/getyii.com.conf",
    "content": "server {\n        charset utf-8;\n\tclient_max_body_size 128M;\n\n\tlisten 80;\n\tserver_name getyii.com www.getyii.com *.dev.www.getyii.com;\n\tindex index.php;\n\tset $rootdir /app/frontend/web;\n\troot $rootdir;\n\n\tlocation / {\n                try_files $uri $uri /index.php?$args;\n\t}\n\n\tlocation ~ \\.php$ {\n                include fastcgi_params;\n                fastcgi_index index.php;\n                fastcgi_param SCRIPT_FILENAME $rootdir/index.php;\n                fastcgi_pass 127.0.0.1:9000;\n\t}\n\n\tlocation ~ /\\.(ht|svn|git) {\n                deny all;\n\t}\n}\n\nserver {\n        charset utf-8;\n\tclient_max_body_size 128M;\n\n\tlisten 80;\n\tserver_name admin.getyii.com *.dev.admin.getyii.com;\n\tindex index.php;\n\tset $rootdir /app/backend/web;\n\troot $rootdir;\n\n\tlocation / {\n                try_files $uri $uri /index.php?$args;\n\t}\n\n\tlocation ~ \\.php$ {\n                include fastcgi_params;\n                fastcgi_index index.php;\n                fastcgi_param SCRIPT_FILENAME $rootdir/index.php;\n                fastcgi_pass 127.0.0.1:9000;\n\t}\n        \n\tlocation ~ /\\.(ht|svn|git) {\n                deny all;\n\t}\n}\n"
  },
  {
    "path": "docker-files/run.sh",
    "content": "#!/bin/bash\n\nset -e -x \n\ncd /app\ncomposer install --prefer-dist --no-interaction --optimize-autoloader\n./init --env=${APP_ENV:-Production} --overwrite=y\n./yii migrate --interactive=0\n\nfunction setEnvironmentVariable() {\n    if [ -z \"$2\" ]; then\n            echo \"Environment variable '$1' not set.\"\n            return\n    fi\n    echo \"env[$1] = \\\"$2\\\" ; automatically add env\" >> /usr/local/etc/php-fpm.conf\n}\n\nsed -i '/automatically add env/d' /usr/local/etc/php-fpm.conf\n\n# Grep all ENV variables\nfor _curVar in `env | awk -F = '{print $1}'`;do\n    # awk has split them by the equals sign\n    # Pass the name and value to our function\n    setEnvironmentVariable ${_curVar} ${!_curVar}\ndone\n\nsupervisord -n\n# service supervisord start\n"
  },
  {
    "path": "environments/dev/backend/config/main-local.php",
    "content": "<?php\n\n$config = [\n    'components' => [\n        'request' => [\n            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation\n            'cookieValidationKey' => '',\n        ],\n    ],\n];\n\nif (!YII_ENV_TEST) {\n    // configuration adjustments for 'dev' environment\n    $config['bootstrap'][] = 'debug';\n    $config['modules']['debug'] = 'yii\\debug\\Module';\n\n    $config['bootstrap'][] = 'gii';\n    $config['modules']['gii'] = 'yii\\gii\\Module';\n}\n\nreturn $config;\n"
  },
  {
    "path": "environments/dev/backend/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/dev/backend/web/index-test.php",
    "content": "<?php\n\n// NOTE: Make sure this file is not accessible when deployed to production\nif (!in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {\n    die('You are not allowed to access this file.');\n}\n\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n\nrequire(__DIR__ . '/../../vendor/autoload.php');\nrequire(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/../../common/config/bootstrap.php');\nrequire(__DIR__ . '/../config/bootstrap.php');\n\n\n$config = require(__DIR__ . '/../../tests/codeception/config/backend/acceptance.php');\n\n(new yii\\web\\Application($config))->run();\n"
  },
  {
    "path": "environments/dev/backend/web/index.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'dev');\n\nrequire(__DIR__ . '/../../vendor/autoload.php');\nrequire(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/../../common/config/bootstrap.php');\nrequire(__DIR__ . '/../config/bootstrap.php');\n\n$config = yii\\helpers\\ArrayHelper::merge(\n    require(__DIR__ . '/../../common/config/main.php'),\n    require(__DIR__ . '/../../common/config/main-local.php'),\n    require(__DIR__ . '/../config/main.php'),\n    require(__DIR__ . '/../config/main-local.php')\n);\n\n$application = new yii\\web\\Application($config);\n$application->run();\n"
  },
  {
    "path": "environments/dev/common/config/db.php",
    "content": "<?php\n\n$MYSQL_PORT_3306_TCP_ADDR = env('MYSQL_PORT_3306_TCP_ADDR', 'localhost');\n$MYSQL_DB_NAME = env('MYSQL_INSTANCE_NAME', 'yii2advanced');\n$MYSQL_USERNAME = env('MYSQL_USERNAME', 'root');\n$MYSQL_PASSWORD = env('MYSQL_PASSWORD', '');\n\n$db = [\n    'class' => 'yii\\db\\Connection',\n    'dsn' => 'mysql:host=' . $MYSQL_PORT_3306_TCP_ADDR . ';dbname=' . $MYSQL_DB_NAME,\n    'username' => $MYSQL_USERNAME,\n    'password' => $MYSQL_PASSWORD,\n    'charset' => 'utf8mb4',\n    'enableSchemaCache' => true,\n    'schemaCacheDuration' => 3600,\n    'schemaCache' => 'cache',\n];\n\nreturn $db;"
  },
  {
    "path": "environments/dev/common/config/main-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/dev/common/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/dev/console/config/main-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/dev/console/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/dev/frontend/config/main-local.php",
    "content": "<?php\n\n$config = [\n    'components' => [\n        'request' => [\n            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation\n            'cookieValidationKey' => '',\n        ],\n    ],\n];\n\nif (!YII_ENV_TEST) {\n    // configuration adjustments for 'dev' environment\n    $config['bootstrap'][] = 'debug';\n    $config['modules']['debug'] = 'yii\\debug\\Module';\n\n    $config['bootstrap'][] = 'gii';\n    $config['modules']['gii'] = 'yii\\gii\\Module';\n}\n\nreturn $config;\n"
  },
  {
    "path": "environments/dev/frontend/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/dev/frontend/web/index-test.php",
    "content": "<?php\n\n// NOTE: Make sure this file is not accessible when deployed to production\nif (!in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {\n    die('You are not allowed to access this file.');\n}\n\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n\nrequire(__DIR__ . '/../../vendor/autoload.php');\nrequire(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/../../common/config/bootstrap.php');\nrequire(__DIR__ . '/../config/bootstrap.php');\n\n$config = require(__DIR__ . '/../../tests/codeception/config/frontend/acceptance.php');\n\n(new yii\\web\\Application($config))->run();\n"
  },
  {
    "path": "environments/dev/frontend/web/index.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'dev');\n\nrequire(__DIR__ . '/../../vendor/autoload.php');\nrequire(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/../../common/config/bootstrap.php');\nrequire(__DIR__ . '/../config/bootstrap.php');\n\n$config = yii\\helpers\\ArrayHelper::merge(\n    require(__DIR__ . '/../../common/config/main.php'),\n    require(__DIR__ . '/../../common/config/main-local.php'),\n    require(__DIR__ . '/../config/main.php'),\n    require(__DIR__ . '/../config/main-local.php')\n);\n\n$application = new yii\\web\\Application($config);\n$application->run();\n"
  },
  {
    "path": "environments/dev/yii",
    "content": "#!/usr/bin/env php\n<?php\n/**\n * Yii console bootstrap file.\n *\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'dev');\n\n// fcgi doesn't have STDIN and STDOUT defined by default\ndefined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));\ndefined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));\n\nrequire(__DIR__ . '/vendor/autoload.php');\nrequire(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/common/config/bootstrap.php');\nrequire(__DIR__ . '/console/config/bootstrap.php');\n\n$config = yii\\helpers\\ArrayHelper::merge(\n    require(__DIR__ . '/common/config/main.php'),\n    require(__DIR__ . '/common/config/main-local.php'),\n    require(__DIR__ . '/console/config/main.php'),\n    require(__DIR__ . '/console/config/main-local.php')\n);\n\n$application = new yii\\console\\Application($config);\n$exitCode = $application->run();\nexit($exitCode);\n"
  },
  {
    "path": "environments/index.php",
    "content": "<?php\n/**\n * The manifest of files that are local to specific environment.\n * This file returns a list of environments that the application\n * may be installed under. The returned data must be in the following\n * format:\n *\n * ```php\n * return [\n *     'environment name' => [\n *         'path' => 'directory storing the local files',\n *         'setWritable' => [\n *             // list of directories that should be set writable\n *         ],\n *         'setExecutable' => [\n *             // list of directories that should be set executable\n *         ],\n *         'setCookieValidationKey' => [\n *             // list of config files that need to be inserted with automatically generated cookie validation keys\n *         ],\n *         'createSymlink' => [\n *             // list of symlinks to be created. Keys are symlinks, and values are the targets.\n *         ],\n *     ],\n * ];\n * ```\n */\nreturn [\n    'Development' => [\n        'path' => 'dev',\n        'setWritable' => [\n            'backend/runtime',\n            'backend/web/assets',\n            'frontend/runtime',\n            'frontend/web/assets',\n        ],\n        'setExecutable' => [\n            'yii',\n        ],\n        'setCookieValidationKey' => [\n            'backend/config/main-local.php',\n            'frontend/config/main-local.php',\n        ],\n    ],\n    'Production' => [\n        'path' => 'prod',\n        'setWritable' => [\n            'backend/runtime',\n            'backend/web/assets',\n            'frontend/runtime',\n            'frontend/web/assets',\n        ],\n        'setExecutable' => [\n            'yii',\n        ],\n        'setCookieValidationKey' => [\n            'backend/config/main-local.php',\n            'frontend/config/main-local.php',\n        ],\n    ],\n];\n"
  },
  {
    "path": "environments/prod/backend/config/main-local.php",
    "content": "<?php\nreturn [\n    'components' => [\n        'request' => [\n            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation\n            'cookieValidationKey' => '',\n        ],\n    ],\n];\n"
  },
  {
    "path": "environments/prod/backend/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/prod/backend/web/index.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', false);\ndefined('YII_ENV') or define('YII_ENV', 'prod');\n\nrequire(__DIR__ . '/../../vendor/autoload.php');\nrequire(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/../../common/config/bootstrap.php');\nrequire(__DIR__ . '/../config/bootstrap.php');\n\n$config = yii\\helpers\\ArrayHelper::merge(\n    require(__DIR__ . '/../../common/config/main.php'),\n    require(__DIR__ . '/../../common/config/main-local.php'),\n    require(__DIR__ . '/../config/main.php'),\n    require(__DIR__ . '/../config/main-local.php')\n);\n\n$application = new yii\\web\\Application($config);\n$application->run();\n"
  },
  {
    "path": "environments/prod/common/config/db.php",
    "content": "<?php\n\n$MYSQL_PORT_3306_TCP_ADDR = env('MYSQL_PORT_3306_TCP_ADDR', 'localhost');\n$MYSQL_DB_NAME = env('MYSQL_INSTANCE_NAME', 'yii2advanced');\n$MYSQL_USERNAME = env('MYSQL_USERNAME', 'root');\n$MYSQL_PASSWORD = env('MYSQL_PASSWORD', '');\n\n$db = [\n    'class' => 'yii\\db\\Connection',\n    'dsn' => 'mysql:host=' . $MYSQL_PORT_3306_TCP_ADDR . ';dbname=' . $MYSQL_DB_NAME,\n    'username' => $MYSQL_USERNAME,\n    'password' => $MYSQL_PASSWORD,\n    'charset' => 'utf8mb4',\n    'enableSchemaCache' => true,\n    'schemaCacheDuration' => 3600,\n    'schemaCache' => 'cache',\n];\n\nreturn $db;"
  },
  {
    "path": "environments/prod/common/config/main-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/prod/common/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/prod/console/config/main-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/prod/console/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/prod/frontend/config/main-local.php",
    "content": "<?php\nreturn [\n    'components' => [\n        'request' => [\n            // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation\n            'cookieValidationKey' => '',\n        ],\n    ],\n];\n"
  },
  {
    "path": "environments/prod/frontend/config/params-local.php",
    "content": "<?php\nreturn [\n];\n"
  },
  {
    "path": "environments/prod/frontend/web/index.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', false);\ndefined('YII_ENV') or define('YII_ENV', 'prod');\n\nrequire(__DIR__ . '/../../vendor/autoload.php');\nrequire(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/../../common/config/bootstrap.php');\nrequire(__DIR__ . '/../config/bootstrap.php');\n\n$config = yii\\helpers\\ArrayHelper::merge(\n    require(__DIR__ . '/../../common/config/main.php'),\n    require(__DIR__ . '/../../common/config/main-local.php'),\n    require(__DIR__ . '/../config/main.php'),\n    require(__DIR__ . '/../config/main-local.php')\n);\n\n$application = new yii\\web\\Application($config);\n$application->run();\n"
  },
  {
    "path": "environments/prod/yii",
    "content": "#!/usr/bin/env php\n<?php\n/**\n * Yii console bootstrap file.\n *\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\ndefined('YII_DEBUG') or define('YII_DEBUG', false);\ndefined('YII_ENV') or define('YII_ENV', 'prod');\n\n// fcgi doesn't have STDIN and STDOUT defined by default\ndefined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));\ndefined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));\n\nrequire(__DIR__ . '/vendor/autoload.php');\nrequire(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');\nrequire(__DIR__ . '/common/config/bootstrap.php');\nrequire(__DIR__ . '/console/config/bootstrap.php');\n\n$config = yii\\helpers\\ArrayHelper::merge(\n    require(__DIR__ . '/common/config/main.php'),\n    require(__DIR__ . '/common/config/main-local.php'),\n    require(__DIR__ . '/console/config/main.php'),\n    require(__DIR__ . '/console/config/main-local.php')\n);\n\n$application = new yii\\console\\Application($config);\n$exitCode = $application->run();\nexit($exitCode);\n"
  },
  {
    "path": "frontend/assets/AppAsset.php",
    "content": "<?php\n/**\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\nnamespace frontend\\assets;\nuse Yii;\nuse yii\\web\\AssetBundle;\n\n/**\n * @author Qiang Xue <qiang.xue@gmail.com>\n * @since 2.0\n */\nclass AppAsset extends AssetBundle\n{\n    public $basePath = '@webroot';\n    public $baseUrl = '@web';\n\n    public $css = [\n        'css/global.css',\n        'css/site.css',  //site.css or site-ruyi.css\n    ];\n\n    public $js = [\n        'js/emojify.min.js',\n        'js/main.js',\n        'js/topic.js',\n        'js/jquery.pin.js',\n        'js/nav.js',\n    ];\n\n    public $depends = [\n        'yii\\web\\YiiAsset',\n        'yii\\bootstrap\\BootstrapAsset',\n    ];\n}"
  },
  {
    "path": "frontend/assets/AtJsAsset.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 2016/3/10 11:24\n * description:\n */\n\nnamespace frontend\\assets;\n\n\nuse yii\\web\\AssetBundle;\n\nclass AtJsAsset extends AssetBundle\n{\n    public $basePath = '@webroot';\n    public $baseUrl = '@web';\n\n    public $css = [\n    ];\n\n    public $js = [\n        'js/At.js',\n    ];\n\n    public $depends = [\n        'yii\\web\\YiiAsset',\n        'common\\assets\\AtJs',\n        'common\\assets\\CaretJs',\n    ];\n}"
  },
  {
    "path": "frontend/assets/BowerAsset.php",
    "content": "<?php\nnamespace frontend\\assets;\n\nuse yii\\web\\AssetBundle;\n\n/**\n * @author forecho <caizhenghai@gmail.com>\n */\nclass BowerAsset extends AssetBundle\n{\n    public $sourcePath = '@bower';\n    public $baseUrl = '@bower';\n\n    public $css = [\n        'highlightjs/styles/darkula.css',\n        'pace/themes/green/pace-theme-minimal.css',\n    ];\n\n    public $js = [\n        'highlightjs/highlight.pack.js',\n        'localforage/dist/localforage.min.js',\n        'pace/pace.min.js',\n    ];\n}\n"
  },
  {
    "path": "frontend/assets/EditorAsset.php",
    "content": "<?php\n\nnamespace frontend\\assets;\nuse Yii;\nuse yii\\web\\AssetBundle;\n\nclass EditorAsset extends AssetBundle\n{\n    public $basePath = '@webroot';\n    public $baseUrl = '@web';\n\n    public $css = [\n    ];\n\n    public $js = [\n        'js/editor.js',\n    ];\n\n    public $depends = [\n        'yii\\web\\YiiAsset',\n        'common\\assets\\AtJs',\n        'common\\assets\\CaretJs',\n//        'common\\assets\\DropzoneJs',\n    ];\n}"
  },
  {
    "path": "frontend/assets/EmojifyAsset.php",
    "content": "<?php\nnamespace frontend\\assets;\n\nuse yii\\web\\AssetBundle;\n\n/**\n * @author forecho <caizhenghai@gmail.com>\n */\nclass EmojifyAsset extends AssetBundle\n{\n    public $sourcePath = '@bower/emojify.js';\n    public $baseUrl = '@bower/emojify.js';\n\n    public $css = [\n    ];\n\n    public $js = [\n        'dist/js/emojify.min.js',\n    ];\n}\n"
  },
  {
    "path": "frontend/behaviors/AfterLoginBehavior.php",
    "content": "<?php\n\nnamespace frontend\\behaviors;\n\nuse Yii;\nuse yii\\base\\Behavior;\nuse yii\\web\\User;\n\n/**\n * after login behavior\n */\nclass AfterLoginBehavior extends Behavior\n{\n    /**\n     * @var int\n     */\n    public $attribute = 'logged_at';\n\n    /**\n     * {@inheritdoc}\n     */\n    public function events()\n    {\n        return [\n            User::EVENT_AFTER_LOGIN => 'afterLogin',\n        ];\n    }\n\n    /**\n     * @param \\yii\\web\\UserEvent $event\n     * @return bool\n     */\n    public function afterLogin($event)\n    {\n        if ($model = $event->identity->userInfo) {\n            $model->login_count += 1;\n            $model->prev_login_time = $model->last_login_time;\n            $model->prev_login_ip = $model->last_login_ip;\n            $model->last_login_time = time();\n            $model->last_login_ip = Yii::$app->getRequest()->getUserIP();\n\n            if (!Yii::$app->session->isActive) {\n                Yii::$app->session->open();\n            }\n            $model->session_id = Yii::$app->session->id;\n            Yii::$app->session->close();\n\n            if ($model->save()) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "frontend/config/.gitignore",
    "content": "main-local.php\nparams-local.php"
  },
  {
    "path": "frontend/config/bootstrap.php",
    "content": "<?php\n"
  },
  {
    "path": "frontend/config/main.php",
    "content": "<?php\n$params = array_merge(\n    require(__DIR__ . '/../../common/config/params.php'),\n    require(__DIR__ . '/../../common/config/params-local.php'),\n    require(__DIR__ . '/params.php'),\n    require(__DIR__ . '/params-local.php')\n);\n\nreturn [\n    'id' => 'app-frontend',\n    'basePath' => dirname(__DIR__),\n    'bootstrap' => ['log'],\n    'controllerNamespace' => 'frontend\\controllers',\n    'components' => [\n        'urlManager' => [\n            'enablePrettyUrl' => true,\n            'showScriptName' => false,\n            'rules' => [\n                '/' => 'topic/default/index',\n                '<alias:login|logout|about|tags|getstart|signup|contact|users|markdown|at-users>' => 'site/<alias>',\n                '<alias:search>' => 'topic/default/<alias>',\n                'member/<username:\\w+>' => 'user/default/show',\n                'member/<username:\\w+>/<alias:point|post|favorite>' => 'user/default/<alias>',\n                '<controller:\\w+>/<action:\\w+>/<id:\\d+>' => '<controller>/<action>',\n                'member/<action>/<type:\\w+>/<id:\\d+>' => 'user/action/<action>',\n                'tag/<tag:\\w+>' => 'topic/default/index/',\n                'node/<node:[0-9a-zA-Z\\-]+>' => 'topic/default/index',\n                'topic/<id:[0-9a-zA-Z\\-]+>' => 'topic/default/view',\n                '<module>/<controller:\\w+>/<action:\\w+>/<id:\\d+>' => '<module>/<controller>/<action>',\n            ],\n        ],\n        'user' => [\n            'identityClass' => 'common\\models\\User',\n            'enableAutoLogin' => true,\n            'as afterLogin' => 'frontend\\behaviors\\AfterLoginBehavior',\n        ],\n        'xunsearch' => [\n            'class' => 'hightman\\xunsearch\\Connection', // 此行必须\n            'iniDirectory' => '@frontend/config',    // 搜索 ini 文件目录，默认：@vendor/hightman/xunsearch/app\n            'charset' => 'utf-8',   // 指定项目使用的默认编码，默认即时 utf-8，可不指定\n        ],\n        'authClientCollection' => [\n            'class' => 'yii\\authclient\\Collection',\n            'clients' => [\n                // 'google' => [\n                //     'class' => 'yii\\authclient\\clients\\GoogleOpenId'\n                // ],\n                'github' => [\n                    'class' => 'yii\\authclient\\clients\\GitHub',\n                    'clientId' => 'github_client_id',\n                    'clientSecret' => 'github_client_secret',\n                    'viewOptions' => [\n                        'popupWidth' => 820,\n                        'popupHeight' => 600,\n                    ]\n                ],\n            ],\n        ],\n        'i18n' => [\n            'translations' => [\n                'exception*' => [\n                    'class' => 'yii\\i18n\\PhpMessageSource',\n                    'basePath' => '@frontend/messages',\n                    'fileMap' => [\n                        'app' => 'app.php',\n                    ],\n                ],\n            ],\n        ],\n        'errorHandler' => [\n            'errorAction' => 'site/error',\n        ],\n    ],\n    'modules' => [\n        'user' => [\n            'class' => 'frontend\\modules\\user\\Module',\n        ],\n        'topic' => [\n            'class' => 'frontend\\modules\\topic\\Module',\n        ],\n        'nav' => [\n            'class' => 'frontend\\modules\\nav\\Module',\n        ],\n        'tweet' => [\n            'class' => 'frontend\\modules\\tweet\\Module',\n        ],\n    ],\n    'params' => $params,\n];\n"
  },
  {
    "path": "frontend/config/params.php",
    "content": "<?php\nreturn [\n    'adminEmail' => 'admin@example.com',\n    'donateNode' => ['tricks'], // 开启打赏分类\n    'loginNode' => ['jobs'], // 需要登录才能访问的分类\n    'donateTag' => ['求打赏', '技巧库'], // 开启标签\n    'postingIntervalLimit' => 3600, // 限制发帖间隔，单位秒。默认是 1 个小时\n    'setting' => [\n        'xunsearch' => false, // true 表示开启 GetYii xunsearch 搜索功能，默认不开启\n    ],\n];\n"
  },
  {
    "path": "frontend/config/search.ini",
    "content": "project.name = getyii\r\nproject.default_charset = utf-8\r\nserver.index = 8383\r\nserver.search = 8384\r\n\r\n[topic_id]\r\ntype = id\r\n\r\n[title]\r\ntype = title\r\n\r\n[content]\r\ntype = body\r\n\r\n[status]\r\nindex = self\r\ntokenizer = full\r\n\r\n[updated_at]\r\ntype = numeric"
  },
  {
    "path": "frontend/controllers/NotificationController.php",
    "content": "<?php\n\nnamespace frontend\\controllers;\n\nuse common\\models\\User;\nuse common\\services\\UserService;\nuse Yii;\nuse frontend\\models\\Notification;\nuse yii\\data\\ActiveDataProvider;\nuse yii\\filters\\AccessControl;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\web\\Controller;\nuse yii\\web\\NotFoundHttpException;\nuse yii\\filters\\VerbFilter;\n\n/**\n * NotificationController implements the CRUD actions for Notification model.\n */\nclass NotificationController extends Controller\n{\n    public function behaviors()\n    {\n        return ArrayHelper::merge(parent::behaviors(), [\n            'verbs' => [\n                'class' => VerbFilter::className(),\n                'actions' => [\n                    'delete' => ['post'],\n                    'clear' => ['post'],\n                ],\n            ],\n            'access' => [\n                'class' => AccessControl::className(),\n                'rules' => [\n                    ['allow' => true, 'actions' => ['index', 'count'], 'roles' => ['@']],\n                    ['allow' => true, 'actions' => ['delete', 'clear'], 'verbs' => ['POST'], 'roles' => ['@']],\n                ]\n            ]\n        ]);\n    }\n\n    /**\n     * Lists all Notification models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $dataProvider = new ActiveDataProvider([\n            'query' => Notification::find()->where(['user_id' => Yii::$app->user->id]),\n            'sort' => ['defaultOrder' => [\n                'created_at' => SORT_DESC,\n                'id' => SORT_ASC,\n            ]]\n        ]);\n        $notifyCount = UserService::findNotifyCount();\n        UserService::clearNotifyCount();\n        return $this->render('index', [\n            'dataProvider' => $dataProvider,\n            'notifyCount' => $notifyCount,\n        ]);\n    }\n\n    /**\n     * 返回通知条数\n     * @return mixed\n     */\n    public function actionCount()\n    {\n        $model = User::findOne(Yii::$app->user->id);\n        return $model->notification_count;\n    }\n\n    /**\n     * Deletes an existing Notification model.\n     * If deletion is successful, the browser will be redirected to the 'index' page.\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionDelete($id)\n    {\n        $this->findModel($id)->delete();\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * 清空通知\n     * @return \\yii\\web\\Response\n     * @throws NotFoundHttpException\n     * @throws \\Exception\n     */\n    public function actionClear()\n    {\n        Notification::deleteAll(['user_id' => Yii::$app->user->id]);\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * Finds the Notification model based on its primary key value.\n     * If the model is not found, a 404 HTTP exception will be thrown.\n     * @param integer $id\n     * @return Notification the loaded model\n     * @throws NotFoundHttpException if the model cannot be found\n     */\n    protected function findModel($id)\n    {\n        if (($model = Notification::findOne($id)) !== null) {\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n}\n"
  },
  {
    "path": "frontend/controllers/PostTagController.php",
    "content": "<?php\nnamespace frontend\\controllers;\n\nuse Yii;\nuse yii\\helpers\\ArrayHelper;\nuse common\\models\\PostTagSearch;\nuse common\\components\\Controller;\n\n/**\n * PostTagController implements the CRUD actions for PostTag model.\n */\nclass PostTagController extends Controller\n{\n    /**\n     * Lists all PostTag models.\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        $searchModel = new PostTagSearch();\n        $params = Yii::$app->request->queryParams;\n        $dataProvider = $searchModel->search($params);\n        //ajax\n        if (Yii::$app->request->getIsAjax()) {\n            return json_encode(ArrayHelper::getColumn($dataProvider->getModels(), function ($model) {\n                return $model->getAttributes(['name']);\n            }));\n        }\n        return $this->render('index', [\n            'searchModel' => $searchModel,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n}"
  },
  {
    "path": "frontend/controllers/SiteController.php",
    "content": "<?php\n\nnamespace frontend\\controllers;\n\nuse common\\components\\Controller;\nuse common\\helpers\\Arr;\nuse common\\helpers\\UploadHelper;\nuse common\\models\\LoginForm;\nuse common\\models\\Post;\nuse common\\models\\PostComment;\nuse common\\models\\PostTag;\nuse common\\models\\RightLink;\nuse common\\models\\Session;\nuse common\\models\\User;\nuse common\\services\\UserService;\nuse Da\\QrCode\\Action\\QrCodeAction;\nuse frontend\\models\\ContactForm;\nuse frontend\\models\\PasswordResetRequestForm;\nuse frontend\\models\\ResetPasswordForm;\nuse frontend\\models\\SignupForm;\nuse frontend\\modules\\user\\models\\UserAccount;\nuse Yii;\nuse yii\\base\\InvalidParamException;\nuse yii\\base\\Model;\nuse yii\\filters\\AccessControl;\nuse yii\\filters\\VerbFilter;\nuse yii\\helpers\\Json;\nuse yii\\web\\BadRequestHttpException;\nuse yii\\web\\NotFoundHttpException;\nuse yii\\web\\Response;\nuse yii\\widgets\\ActiveForm;\n\n/**\n * Site controller\n */\nclass SiteController extends Controller\n{\n    /**\n     * @inheritdoc\n     */\n    public function behaviors()\n    {\n        return Arr::merge(parent::behaviors(), [\n            'access' => [\n                'class' => AccessControl::className(),\n                'only' => ['logout', 'signup', 'connect', 'upload'],\n                'rules' => [\n                    ['actions' => ['signup', 'connect'], 'allow' => true, 'roles' => ['?']],\n                    ['actions' => ['logout', 'upload'], 'allow' => true, 'roles' => ['@']],\n                ],\n            ],\n            'verbs' => [\n                'class' => VerbFilter::className(),\n                'actions' => ['logout' => ['post']],\n            ],\n        ]);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function actions()\n    {\n        return [\n            'error' => [\n                'class' => 'yii\\web\\ErrorAction',\n            ],\n            'qr' => [\n                'class' => QrCodeAction::className(),\n                'component' => 'qr' // if configured in our app as `qr`\n            ],\n            'captcha' => [\n                'class' => 'yii\\captcha\\CaptchaAction',\n                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,\n            ],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function beforeAction($action)\n    {\n        if ($action->id == 'upload') {\n            $this->enableCsrfValidation = false;\n        }\n        return parent::beforeAction($action);\n    }\n\n    public function actionIndex()\n    {\n        $topics = Post::find()->with('user',\n            'category')->limit(20)->where(['status' => 2])->orderBy(['created_at' => SORT_DESC])->all();\n        $users = UserService::findActiveUser(12);\n        $headline = Arr::getColumn(RightLink::find()->where(['type' => RightLink::RIGHT_LINK_TYPE_HEADLINE])->all(),\n            'content');\n\n        $statistics = [];\n        $statistics['post_count'] = Post::find()->count();\n        $statistics['comment_count'] = PostComment::find()->count();\n        $statistics['online_count'] = Session::find()->where(['>', 'expire', time()])->count();\n\n        return $this->render('index', [\n            'topics' => $topics,\n            'users' => $users,\n            'statistics' => $statistics,\n            'headline' => Arr::arrayRandomAssoc($headline),\n        ]);\n    }\n\n    public function actionLogin()\n    {\n        if (!\\Yii::$app->user->isGuest) {\n            return $this->goHome();\n        }\n\n        $model = new LoginForm();\n        if ($model->load(Yii::$app->request->post()) && $model->login()) {\n            return $this->goBack();\n        } else {\n            return $this->render('login', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    public function actionLogout()\n    {\n        Yii::$app->user->logout();\n\n        return $this->goHome();\n    }\n\n    public function actionContact()\n    {\n        $model = new ContactForm();\n        if ($model->load(Yii::$app->request->post()) && $model->validate()) {\n            if ($model->sendEmail(Yii::$app->params['adminEmail'])) {\n                Yii::$app->session->setFlash('success',\n                    'Thank you for contacting us. We will respond to you as soon as possible.');\n            } else {\n                Yii::$app->session->setFlash('error', 'There was an error sending email.');\n            }\n\n            return $this->refresh();\n        } else {\n            return $this->render('contact', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    public function actionAbout()\n    {\n        return $this->render('about');\n    }\n\n    public function actionTags()\n    {\n        $tags = PostTag::find()->orderBy('updated_at DESC')->all();\n\n        return $this->render('tags', [\n            'tags' => $tags,\n        ]);\n    }\n\n    public function actionContributors()\n    {\n        return $this->render('contributors');\n    }\n\n    public function actionGetstart()\n    {\n        return $this->render('getstart');\n    }\n\n    public function actionUsers()\n    {\n        $model = UserService::findActiveUser(100);\n        $count = User::find()->where(['status' => 10])->count();\n        return $this->render('users', [\n            'model' => $model,\n            'count' => $count,\n        ]);\n    }\n\n    public function actionAtUsers()\n    {\n        $model = UserService::findActiveUser(400);\n        return Json::encode(Arr::getColumn($model, 'username'));\n    }\n\n    public function actionBook()\n    {\n        return $this->redirect('http://book.getyii.com');\n    }\n\n    public function actionMarkdown()\n    {\n        return $this->render('markdown');\n    }\n\n    public function actionTimeline()\n    {\n        return $this->render('timeline');\n    }\n\n    /**\n     * Displays page where user can create new account that will be connected to social account.\n     * @param integer $account_id\n     * @return string\n     * @throws NotFoundHttpException\n     */\n    public function actionConnect($account_id)\n    {\n        /** @var UserAccount $account */\n        $account = UserAccount::find()->where(['id' => $account_id])->one();\n\n        if ($account === null || $account->getIsConnected()) {\n            throw new NotFoundHttpException;\n        }\n        $accountData = Json::decode($account->data);\n\n        $model = new SignupForm();\n        $model->username = $accountData['login'];\n        $model->email = empty($accountData['email']) ? '' : $accountData['email'];\n\n        $this->performAjaxValidation($model);\n\n        if ($model->load(Yii::$app->request->post())) {\n            if ($user = $model->signup()) {\n                $account->user_id = $user->id;\n                $account->save(false);\n                if (Yii::$app->getUser()->login($user, 1209600)) {\n                    return $this->goHome();\n                }\n            }\n        }\n\n        return $this->render('signup', [\n            'model' => $model,\n        ]);\n    }\n\n    public function actionSignup()\n    {\n        $model = new SignupForm();\n\n        $this->performAjaxValidation($model);\n\n        if ($model->load(Yii::$app->request->post())) {\n            $model->role = User::ROLE_USER;\n            if ($user = $model->signup()) {\n                if (Yii::$app->getUser()->login($user)) {\n                    return $this->goHome();\n                }\n            }\n        }\n\n        return $this->render('signup', [\n            'model' => $model,\n        ]);\n    }\n\n    public function actionRequestPasswordReset()\n    {\n        $model = new PasswordResetRequestForm();\n        if ($model->load(Yii::$app->request->post()) && $model->validate()) {\n            if ($model->sendEmail()) {\n                Yii::$app->getSession()->setFlash('success', 'Check your email for further instructions.');\n\n                return $this->goHome();\n            } else {\n                Yii::$app->getSession()->setFlash('error',\n                    'Sorry, we are unable to reset password for email provided.');\n            }\n        }\n\n        return $this->render('requestPasswordResetToken', [\n            'model' => $model,\n        ]);\n    }\n\n    public function actionResetPassword($token)\n    {\n        try {\n            $model = new ResetPasswordForm($token);\n        } catch (InvalidParamException $e) {\n            throw new BadRequestHttpException($e->getMessage());\n        }\n\n        if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) {\n            Yii::$app->getSession()->setFlash('success', 'New password was saved.');\n\n            return $this->goHome();\n        }\n\n        return $this->render('resetPassword', [\n            'model' => $model,\n        ]);\n    }\n\n    /**\n     *  上传图片\n     * @param $field\n     * @return array\n     */\n    public function actionUpload($field)\n    {\n        Yii::$app->response->format = Response::FORMAT_JSON;\n        $token = params('smToken');\n        $file = UploadHelper::getCurlValue($_FILES[$field]['tmp_name'], $_FILES[$field]['type'],\n            basename($_FILES[$field]['name']));\n        $ch = curl_init();\n        curl_setopt($ch, CURLOPT_URL, 'https://sm.ms/api/v2/upload');\n        curl_setopt($ch, CURLOPT_POST, 1);\n        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);\n        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0');\n        curl_setopt($ch, CURLOPT_POSTFIELDS, ['smfile' => $file]);\n        curl_setopt($ch, CURLOPT_HTTPHEADER, [\n            \"Authorization:\" . $token\n        ]);\n        $response = curl_exec($ch);\n\n        if (curl_errno($ch)) {\n            Yii::error($response, '上传图片失败');\n            $return = ['success' => 0, 'message' => '上传失败'];\n        } else {\n            $array = Json::decode($response);\n            if (!empty($array['data']['url'])) {\n                $return = ['success' => 1, 'message' => '上传成功', 'url' => $array['data']['url']];\n            } else {\n                Yii::error($response, '上传图片失败');\n                $return = ['success' => 0, 'message' => '上传失败'];\n            }\n        }\n        curl_close($ch);\n        return $return;\n    }\n\n    /**\n     * Performs ajax validation.\n     * @param Model $model\n     * @return void\n     * @throws \\yii\\base\\ExitException\n     */\n    protected function performAjaxValidation($model)\n    {\n        if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {\n            Yii::$app->response->format = Response::FORMAT_JSON;\n            Yii::$app->response->data = ActiveForm::validate($model);\n            Yii::$app->response->send();\n            Yii::$app->end();\n        }\n    }\n}\n"
  },
  {
    "path": "frontend/messages/zh-CN/app.php",
    "content": "<?php\n\nreturn [\n    'Topics' => '社区',\n    'Wiki' => 'Wiki',\n    'Users' => '会员',\n    'About' => '关于',\n    'Search' => '搜索',\n    'Login' => '登录',\n    'Logout' => '退出',\n    'Sign up' => '注册',\n    'Notifications' => '通知提醒',\n    'New Topic' => '发布新帖',\n    'Links' => '友情链接',\n    'Same Node Topics' => '节点下其他主题',\n    'Tips and Tricks' => '小贴士',\n    'Site Status' => '统计信息',\n    'Total User' => '社区会员',\n    'Total Topic' => '主题数',\n    'Total Reply' => '回复数',\n    'You dont have permission to proceed.' => '很抱歉, 当前用户没有权限继续操作. <br>有什么问题请联系管理员.',\n    'Permission Deny' => '管理员权限提示',\n    'Notice' => '提示',\n    'Login with Github' => '使用 Github 帐号登录',\n    'User Login Require' => '用户登录提示',\n    'You need to login to proceed.' => '需要登录后才能继续操作. <br>当前只允许通过 Github 帐号登录.',\n    'Create New Account' => '创建新账号',\n    'Avatar' => '头像',\n    'Username' => '用户名',\n    'Email' => '邮箱',\n    'Confirm' => '确定',\n    'Operation Deny' => '操作被禁止',\n    'Sorry, You account is banned.' => '对不起，您的账号已被禁用',\n    'All Nodes' => '节点导航',\n    'My Notifications' => '我的提醒',\n    'Your topic have new reply:' => '回复了你的主题:',\n    'Your follow topic have new reply:' => '回复了你关注的主题:',\n    'Attented topic has new reply:' => '回复了你关注的主题:',\n    'Mention you At:' => '在主题中提及你:',\n    'Mention you topic At:' => '在主题中提及你:',\n    'Mention you tweet At:' => '在动弹中提及你:',\n    'Data has been deleted.' => '信息已被删除.',\n    'You dont have any notice yet!' => '还未收到提醒!',\n    'About Us' => '关于我们',\n    'Excellent Topics' => '社区精华帖',\n    'More Excellent Topics' => '查看更多精华帖',\n    'Community Wiki' => '社区 Wiki',\n    'Dont have any data Yet' => '还未有主题',\n    'Recent' => '最近发表',\n    'Excellent' => '精华主题',\n    'Vote' => '最多投票',\n    'Noreply' => '无人问津',\n    'Publish' => '发布',\n    'at' => '于',\n    'Last Reply by' => '最后由',\n    'Reads' => '阅读',\n    'Are you sure want to delete is topic?' => '确定要删除此主题吗?',\n    'This topic has been mark as Excenllent Topic.' => '本帖已被设为精华帖！',\n    'This is a Community Wiki.' => '本帖已被设为社区 Wiki！',\n    'Share on Weibo' => '分享到微博',\n    'Share on Twitter' => '分享到 Twitter',\n    'Share on Facebook' => '分享到 Facebook',\n    'Share on Google Plus' => '分享到 Google Plus',\n    'Cancel' => '取消',\n    'Attent' => '关注',\n    'Favorite' => '收藏',\n    'Mark as Excellent' => '设为推荐主题',\n    'Mark as Community Wiki' => '加入到社区 Wiki',\n    'Pin it on To' => '置顶此主题',\n    'Delete' => '删除',\n    'Edit' => '编辑',\n    'Preview' => '预览',\n    'No content.' => '没有内容',\n    'Please using markdown.' => '请使用 Markdown 格式书写 ;-)',\n    'Current Node' => '当前节点',\n    'Pick a node' => '请选择节点',\n    'Please write down a topic' => '请填写标题',\n    'Writting Format Notice' => '格式说明',\n    'This kind of topic is not allowed.' => '以下类型的信息会污染我们的社区',\n    'We can benefit from it.' => '在高质量优秀社区的我们',\n    'Received {0} reply' => '共收到 {0} 条回复',\n    'User ID:' => '用户 ID:',\n    'Real Name' => '姓名',\n    'Company' => '公司',\n    'City' => '城市',\n    'Blog' => '博客',\n    'Signature' => '签名',\n    'Edit Profile' => '编辑个人资料',\n    'Are you sure want to block this User?' => '您确定要封停该用户吗？',\n    'Are you sure want to unblock this User?' => '您确定要解封该用户吗？',\n    'Unblock User' => '解封用户',\n    'Block User' => '封停用户',\n    'This user is banned!' => '该用户已被封停',\n    'Basic Info' => '个人信息',\n    'Favorites' => '收藏',\n    'Replies' => '回复',\n    'avatar_notice' => '如需修改头像，请到 <a href=\"https://github.com/settings/profile\" target=\"_blank\">Github 的个人设置</a> 页面修改, 然后点击链接 ',\n    'Update Cache' => '更新缓存',\n    'twitter_placeholder' => '你的 Twitter 帐号, 不需要加前缀 https://twitter.com/',\n    'personal_website_placebolder' => '你的个人网站, 不需要加前缀 http://',\n    'signature_placeholder' => '签名/座右铭',\n    'introduction_placeholder' => '个人简介',\n    'Dont have any favorites yet' => '还未收藏任何主题',\n    'Newly Registered User List' => '新加入的会员列表',\n    'Reply List' => '主题列表',\n    'Topic List' => '主题列表',\n    'Dont have any comment yet' => '还未留下任何回复',\n    'Recent Replies' => '最新回复',\n    'Recent Topics' => '最近主题',\n    'Reply' => '回复',\n    'User Login Required for commenting.' => '需要登录后才能发表回复.',\n    'site_intro' => 'Get Yii，对！没错！这里就是 Yii 社区，我们想做国内最权威的 Yii 社区，拥有国内所有资深的 Yii 工程师。',\n    'contributing' => '功能正在完善中, 欢迎 <i class=\"fa fa-github\" style=\"font-size:15px\"></i> <a href=\"https://github.com/summerblue/phphub\" target=\"_blank\">贡献代码</a> 或 <a href=\"https://github.com/summerblue/phphub/issues\" target=\"_blank\">提交 Issue</a>.',\n    'be_nice' => '我们希望 PHPHub 能够成为技术氛围最好的 PHP 社区，而实现这个目标，需要我们所有人的共同努力：友善，公平，尊重知识和事实。',\n    'publish_typography' => '请注意单词拼写，以及中英文排版，<a href=\"https://github.com/sparanoid/chinese-copywriting-guidelines\">参考此页</a>',\n    'publish_markdown' => '支持 Markdown 格式, <strong>**粗体**</strong>、~~删除线~~、<code>`单行代码`</code>, 更多语法请见这里 <a href=\"https://github.com/riku/Markdown-Syntax-CN/blob/master/syntax.md\">Markdown 语法</a>',\n    'publish_emoji' => '支持表情，见 <a href=\"http://www.emoji-cheat-sheet.com\" target=\"_blank\" rel=\"nofollow\">Emoji cheat sheet</a>',\n    'publish_at_user' => '@name 会链接到用户页面，并会通知他',\n    'publish_image' => '暂不支持上传图片，请使用外链图片。推荐图床：<a href=\"http://drp.io/\" target=\"_blank\" rel=\"nofollow\">drp.io</a> 和 <a href=\"https://imgur.com/\" target=\"_blank\" rel=\"nofollow\">imgur</a>',\n    'Successfully remove attention.' => '成功取消关注',\n    'Successfully_attention' => '成功关注主题, 系统会通知你关于此主题最新的讨论.',\n    'Operation succeeded.' => '操作成功!',\n    'Congratulations and Welcome!' => '恭喜, 你已经成功加入 PHPHub.',\n    'Operation failed!' => '操作失败!',\n    'Favorited your topic:' => '收藏了你的主题',\n    'Thanks your topic:' => '感谢了你的主题',\n    'Attented your topic:' => '关注了你的主题',\n    'Up Vote your topic' => '赞了你的主题',\n    'Up Vote your reply' => '赞了你的回复',\n    'Up Vote your tweet' => '赞了你的动弹',\n    'has mark your topic as wiki:' => '把你的主题收录为社区 Wiki',\n    'has recomended your topic:' => '推荐了你的主题',\n    'Are you sure want to logout?' => '你确定要退出吗?',\n    'No comments' => '暂无回复',\n    'Learning Resources' => '推荐学习资源',\n    'Create New Topic' => '创建新主题',\n    'Can not vote your feedback' => '不允许给自己点赞',\n    'Recomended Resources' => '推荐资源',\n    'Stick' => '置顶',\n    'Recommended' => '推荐',\n    'Refresh cache success' => '刷新缓存成功',\n\n    'Append' => '附言',\n    'Append Content' => '添加附言',\n    'append_notice' => '附加内容, 使用此功能的话, 会给所有参加过讨论的人发送提醒.',\n    'Submit' => '提交',\n    'Close' => '关闭',\n    'Attented topic has new update:' => '关注的话题有新附言',\n    'Commented topic has new update:' => '留言的话题有新附言',\n    'File has to be smaller than 2MB' => '文件最大支持2M',\n    'Document' => '文档',\n\n    'Update Post: ' => '更新话题：',\n    'Data Deleted' => '相关数据已经删除',\n\n    'Online Count' => '当前在线人数',\n    'Post Count' => '主题数',\n    'Comment Count' => '回答数',\n\n    'Donate' => '打赏',\n    'Qr Code' => '二维码',\n    'Status' => '状态',\n    'Save' => '保存',\n    'Description' => '描述',\n\n    'Tweet Content' => '今天你有什么想分享的或者想吐槽的？（你可以 @forecho AT用户，支持 :joy: emoji 表情，支持 #干货分享# 话题功能）',\n    'cc {username} {url}' => '\n> 本文由 [{username}]({url}) 创作，采用 [知识共享署名 3.0 中国大陆许可协议](http://creativecommons.org/licenses/by/3.0/cn) 进行许可。\n可自由转载、引用，但需署名作者且注明文章出处。',\n];"
  },
  {
    "path": "frontend/models/ContactForm.php",
    "content": "<?php\n\nnamespace frontend\\models;\n\nuse Yii;\nuse yii\\base\\Model;\n\n/**\n * ContactForm is the model behind the contact form.\n */\nclass ContactForm extends Model\n{\n    public $name;\n    public $email;\n    public $subject;\n    public $body;\n    public $verifyCode;\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            // name, email, subject and body are required\n            [['name', 'email', 'subject', 'body'], 'required'],\n            // email has to be a valid email address\n            ['email', 'email'],\n            // verifyCode needs to be entered correctly\n            ['verifyCode', 'captcha'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'verifyCode' => 'Verification Code',\n        ];\n    }\n\n    /**\n     * Sends an email to the specified email address using the information collected by this model.\n     *\n     * @param  string  $email the target email address\n     * @return boolean whether the email was sent\n     */\n    public function sendEmail($email)\n    {\n        return Yii::$app->mailer->compose()\n            ->setTo($email)\n            ->setFrom([$this->email => $this->name])\n            ->setSubject($this->subject)\n            ->setTextBody($this->body)\n            ->send();\n    }\n}\n"
  },
  {
    "path": "frontend/models/Notification.php",
    "content": "<?php\n\nnamespace frontend\\models;\n\nuse common\\components\\db\\ActiveRecord;\nuse common\\models\\Post;\nuse common\\models\\User;\nuse Yii;\n\n/**\n * This is the model class for table \"notification\".\n *\n * @property integer $id\n * @property string $from_user_id\n * @property string $user_id\n * @property string $post_id\n * @property string $comment_id\n * @property string $type\n * @property string $data\n * @property string $created_at\n * @property string $updated_at\n */\nclass Notification extends ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%notification}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['from_user_id', 'user_id', 'post_id', 'type'], 'required'],\n            [['from_user_id', 'user_id', 'post_id', 'comment_id', 'created_at', 'updated_at'], 'integer'],\n            [['data'], 'string'],\n            [['type'], 'string', 'max' => 255]\n        ];\n    }\n\n    public function getUser()\n    {\n        return $this->hasOne(User::className(), ['id' => 'user_id']);\n    }\n\n    public function getFromUser()\n    {\n        return $this->hasOne(User::className(), ['id' => 'from_user_id']);\n    }\n\n    public function getPost()\n    {\n        return $this->hasOne(Post::className(), ['id' => 'post_id']);\n    }\n\n    public function getLable($type)\n    {\n        switch ($type) {\n            case 'new_comment':\n                $lable = Yii::t('app', 'Your follow topic have new reply:');\n                break;\n            case 'attention':\n                $lable = Yii::t('app', 'Attented topic has new reply:');\n                break;\n            case 'at':\n                $lable = Yii::t('app', 'Mention you At:');\n                break;\n            case 'at_topic':\n                $lable = Yii::t('app', 'Mention you topic At:');\n                break;\n            case 'at_tweet':\n                $lable = Yii::t('app', 'Mention you tweet At:');\n                break;\n            case 'topic_favorite':\n                $lable = Yii::t('app', 'Favorited your topic:');\n                break;\n            case 'topic_thanks':\n                $lable = Yii::t('app', 'Thanks your topic:');\n                break;\n            case 'topic_follow':\n                $lable = Yii::t('app', 'Attented your topic:');\n                break;\n            case 'topic_like':\n                $lable = Yii::t('app', 'Up Vote your topic');\n                break;\n            case 'tweet_like':\n                $lable = Yii::t('app', 'Up Vote your tweet');\n                break;\n            case 'comment_like':\n                $lable = Yii::t('app', 'Up Vote your reply');\n                break;\n            case 'topic_mark_wiki':\n                $lable = Yii::t('app', 'has mark your topic as wiki:');\n                break;\n            case 'topic_mark_excellent':\n                $lable = Yii::t('app', 'has recomended your topic:');\n                break;\n            case 'comment_append':\n                $lable = Yii::t('app', 'Commented topic has new update:');\n                break;\n            case 'attention_append':\n                $lable = Yii::t('app', 'Attented topic has new update:');\n                break;\n\n            default:\n                $lable = '';\n                break;\n        }\n        return $lable;\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id'           => 'ID',\n            'from_user_id' => 'From User ID',\n            'user_id'      => 'User ID',\n            'post_id'      => 'Post ID',\n            'comment_id'   => 'Comment ID',\n            'type'         => 'Type',\n            'data'         => 'Data',\n            'created_at'   => 'Created At',\n            'updated_at'   => 'Updated At',\n        ];\n    }\n\n\n}\n"
  },
  {
    "path": "frontend/models/PasswordResetRequestForm.php",
    "content": "<?php\nnamespace frontend\\models;\n\nuse common\\models\\User;\nuse yii\\base\\Model;\nuse yii\\di\\Container;\nuse Yii;\n\n/**\n * Password reset request form\n */\nclass PasswordResetRequestForm extends Model\n{\n    public $email;\n\n    public function init()\n    {\n        parent::init();\n        Yii::$app->set('mailer', [\n            'class' => 'yii\\swiftmailer\\Mailer',\n            'viewPath' => '@common/mail',\n            'transport' => [\n                'class' => 'Swift_SmtpTransport',\n                'host' => Yii::$app->setting->get('smtpHost'),\n                'username' => Yii::$app->setting->get('smtpUser'),\n                'password' => Yii::$app->setting->get('smtpPassword'),\n                'port' => Yii::$app->setting->get('smtpPort'),\n                // 'mail' => Yii::$app->setting->get('smtpMail'), // 显示地址\n                'encryption' => 'tls',\n            ],\n        ]);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            ['email', 'filter', 'filter' => 'trim'],\n            ['email', 'required'],\n            ['email', 'email'],\n            ['email', 'exist',\n                'targetClass' => '\\common\\models\\User',\n                'filter' => ['status' => User::STATUS_ACTIVE],\n                'message' => 'There is no user with such email.'\n            ],\n        ];\n    }\n\n    /**\n     * Sends an email with a link, for resetting the password.\n     *\n     * @return boolean whether the email was send\n     */\n    public function sendEmail()\n    {\n        /* @var $user User */\n        $user = User::findOne([\n            'status' => User::STATUS_ACTIVE,\n            'email' => $this->email,\n        ]);\n\n        if ($user) {\n            if (!User::isPasswordResetTokenValid($user->password_reset_token)) {\n                $user->generatePasswordResetToken();\n            }\n\n            if ($user->save()) {\n                return \\Yii::$app->mailer->compose('passwordResetToken', ['user' => $user])\n                    ->setFrom([\\Yii::$app->setting->get('smtpUser') => \\Yii::$app->name . ' robot'])\n                    ->setTo($this->email)\n                    ->setSubject('Password reset for ' . \\Yii::$app->name)\n                    ->send();\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "frontend/models/ResetPasswordForm.php",
    "content": "<?php\nnamespace frontend\\models;\n\nuse common\\models\\User;\nuse yii\\base\\InvalidParamException;\nuse yii\\base\\Model;\nuse Yii;\n\n/**\n * Password reset form\n */\nclass ResetPasswordForm extends Model\n{\n    public $password;\n\n    /**\n     * @var \\common\\models\\User\n     */\n    private $_user;\n\n    /**\n     * Creates a form model given a token.\n     *\n     * @param  string                          $token\n     * @param  array                           $config name-value pairs that will be used to initialize the object properties\n     * @throws \\yii\\base\\InvalidParamException if token is empty or not valid\n     */\n    public function __construct($token, $config = [])\n    {\n        if (empty($token) || !is_string($token)) {\n            throw new InvalidParamException('Password reset token cannot be blank.');\n        }\n        $this->_user = User::findByPasswordResetToken($token);\n        if (!$this->_user) {\n            throw new InvalidParamException('Wrong password reset token.');\n        }\n        parent::__construct($config);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            ['password', 'required'],\n            ['password', 'string', 'min' => 6],\n        ];\n    }\n\n    /**\n     * Resets password.\n     *\n     * @return boolean if password was reset.\n     */\n    public function resetPassword()\n    {\n        $user = $this->_user;\n        $user->password = $this->password;\n        $user->removePasswordResetToken();\n\n        return $user->save();\n    }\n}\n"
  },
  {
    "path": "frontend/models/SignupForm.php",
    "content": "<?php\nnamespace frontend\\models;\n\nuse common\\models\\User;\nuse yii\\base\\Model;\nuse Yii;\n\n/**\n * Signup form\n */\nclass SignupForm extends Model\n{\n    public $username;\n    public $email;\n    public $password;\n    public $role;\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            ['username', 'filter', 'filter' => 'trim'],\n            ['username', 'required'],\n            ['username', 'match', 'pattern' => '/^[a-z]\\w*$/i', 'message' => '{attribute}只能为数字和字母'],\n            ['username', 'unique', 'targetClass' => '\\common\\models\\User', 'message' => '此{attribute}已经被使用'],\n            ['username', 'string', 'min' => 4, 'max' => 12],\n\n            ['email', 'filter', 'filter' => 'trim'],\n            ['email', 'required'],\n            ['email', 'email'],\n            ['email', 'unique', 'targetClass' => '\\common\\models\\User', 'message' => '此{attribute}已经被使用'],\n\n            ['password', 'required'],\n            ['password', 'string', 'min' => 6],\n\n            ['role', 'integer'],\n            ['role', 'default', 'value' => User::ROLE_USER],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'username' => '用户名',\n            'password' => '密码',\n            'email' => '邮箱',\n            'role' => '角色',\n        ];\n    }\n\n    /**\n     * Signs user up.\n     *\n     * @return User|null the saved model or null if saving fails\n     */\n    public function signup()\n    {\n        if ($this->validate()) {\n            $user = new User();\n            $user->username = $this->username;\n            $user->email = $this->email;\n            $user->role = $this->role;\n            $user->setPassword($this->password);\n            $user->generateAuthKey();\n            $user->save();\n            return $user;\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "frontend/modules/nav/Module.php",
    "content": "<?php\n\nnamespace frontend\\modules\\nav;\n\nclass Module extends \\yii\\base\\Module\n{\n    public $controllerNamespace = 'frontend\\modules\\nav\\controllers';\n\n    public function init()\n    {\n        parent::init();\n\n        // custom initialization code goes here\n    }\n}\n"
  },
  {
    "path": "frontend/modules/nav/controllers/DefaultController.php",
    "content": "<?php\n\nnamespace frontend\\modules\\nav\\controllers;\n\nuse common\\components\\Controller;\nuse common\\models\\Nav;\n\nclass DefaultController extends Controller\n{\n    public function actionIndex()\n    {\n        $nav = Nav::find()->orderBy('order asc')->all();\n        return $this->render('index', ['nav' => $nav]);\n    }\n}\n"
  },
  {
    "path": "frontend/modules/nav/views/default/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\Menu;\nuse yii\\widgets\\ListView;\nuse common\\models\\NavUrl;\n\n\n$this->title = '网站导航';\n\n?>\n\n<style type=\"text/css\">\n    .nav-item {\n        height: 35px;\n    }\n</style>\n<div class=\"nav-index col-md-2\">\n    <div class=\"panel panel-default corner-radius pinned\">\n        <div class=\"panel-heading text-center\">\n            <h3 class=\"panel-title\"><span class=\"glyphicon glyphicon-folder-open\" aria-hidden=\"true\"></span> 导航栏目</h3>\n        </div>\n        <div class=\"panel-body text-center\" style=\"padding-top: 5px;\">\n            <div class=\"list-group \">\n                <?php foreach($nav as $key => $item): ?>\n                <a href=\"#<?php echo $item->alias; ?>\" class=\"list-group-item\"><?php echo $item->name; ?></a>\n                <?php endforeach ?>\n            </div>\n        </div>\n    </div>\n</div>\n\n\n<div class=\"nav-index col-md-10\">\n    <?php foreach($nav as $key => $item): ?>\n    <div class=\"panel panel-default corner-radius\" id=\"<?php echo $item->alias; ?>\">\n        <div class=\"panel-heading text-left\">\n            <h3 class=\"panel-title\"><?php echo $item->name; ?></h3>\n        </div>\n        <div class=\"panel-body text-left\">\n            <div class=\"row\">\n                <?php $NavUrl = NavUrl::find()->where(['nav_id' => $item->id ])->orderBy('order asc')->all(); ?>\n                <?php if($NavUrl): ?>\n                    <?php foreach($NavUrl as $sub_key => $sub_item): ?>\n                        <div class=\"col-md-2 nav-item\"><a href=\"<?php echo $sub_item->url; ?>\" target=\"_blank\" data-toggle=\"tooltip\" data-placement=\"top\"\n                                                  title=\"<?php echo $sub_item->description; ?>\"><?php echo $sub_item->title; ?></a></div>\n                    <?php endforeach ?>\n                <?php  endif; ?>\n            </div>\n        </div>\n    </div>\n    <?php endforeach ?>\n</div>\n\n"
  },
  {
    "path": "frontend/modules/topic/Module.php",
    "content": "<?php\n\nnamespace frontend\\modules\\topic;\n\nclass Module extends \\yii\\base\\Module\n{\n    public $controllerNamespace = 'frontend\\modules\\topic\\controllers';\n\n    public function init()\n    {\n        parent::init();\n\n        // custom initialization code goes here\n    }\n}\n"
  },
  {
    "path": "frontend/modules/topic/controllers/CommentController.php",
    "content": "<?php\n\nnamespace frontend\\modules\\topic\\controllers;\n\nuse common\\models\\UserInfo;\nuse common\\services\\NotificationService;\nuse common\\services\\PostService;\nuse common\\services\\TopicService;\nuse frontend\\models\\Notification;\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\user\\models\\UserMeta;\nuse Yii;\nuse common\\models\\PostComment;\nuse common\\components\\Controller;\nuse yii\\filters\\AccessControl;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\web\\NotFoundHttpException;\nuse yii\\filters\\VerbFilter;\n\n/**\n * CommentController implements the CRUD actions for PostComment model.\n */\nclass CommentController extends Controller\n{\n    public function behaviors()\n    {\n        return ArrayHelper::merge(parent::behaviors(), [\n            'verbs' => [\n                'class' => VerbFilter::className(),\n                'actions' => [\n                    'delete' => ['post'],\n                ],\n            ],\n            'access' => [\n                'class' => AccessControl::className(),\n                'rules' => [\n                    // 登录用户POST操作\n                    ['allow' => true, 'actions' => ['delete'], 'verbs' => ['POST'], 'roles' => ['@']],\n                    // 登录用户才能操作\n                    ['allow' => true, 'actions' => ['create', 'update'], 'roles' => ['@']],\n                ]\n            ],\n        ]);\n    }\n\n    /**\n     * 创建回复\n     * @param $id\n     * @return PostComment|\\yii\\web\\Response\n     */\n    public function actionCreate($id)\n    {\n        $model = new PostComment();\n        if ($model->load(Yii::$app->request->post())) {\n            $topService = new TopicService();\n            if (!$topService->filterContent($model->comment)) {\n                $model->addError('comment', '回复内容请勿回复无意义的内容，如你想收藏或赞等功能，请直接操作这篇帖子。');\n                return $this->redirect(['/topic/default/view', 'id' => $id]);\n            }\n            $model->user_id = Yii::$app->user->id;\n            $model->post_id = $id;\n            $model->ip = Yii::$app->getRequest()->getUserIP();\n            if ($model->save()) {\n                $this->flash(\"回复成功\", 'success');\n            } else {\n                $this->flash(array_values($model->getFirstErrors())[0], 'warning');\n            }\n            return $this->redirect(['/topic/default/view', 'id' => $id]);\n        }\n        return $model;\n    }\n\n    /**\n     * 修改回复\n     * @param $id\n     * @return string|\\yii\\web\\Response\n     * @throws NotFoundHttpException\n     */\n    public function actionUpdate($id)\n    {\n        $model = PostComment::findComment($id);\n        if (!$model->isCurrent()) {\n            throw new NotFoundHttpException();\n        }\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            return $this->redirect(['/topic/default/view', 'id' => $model->post_id]);\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * 伪删除\n     * @param $id\n     * @return \\yii\\web\\Response\n     * @throws NotFoundHttpException\n     */\n    public function actionDelete($id)\n    {\n        $model = PostComment::findComment($id);\n        if (!$model->isCurrent()) {\n            throw new NotFoundHttpException();\n        }\n        // 事物 暂时数据库类型不支持 无效\n        $transaction = \\Yii::$app->db->beginTransaction();\n        $updateComment = $model->updateCounters(['status' => -1]);\n        $updateNotify = Notification::updateAll(['status' => 0], ['comment_id' => $model->id]);\n        $updateTopic = Topic::updateAllCounters(['comment_count' => -1], ['id' => $model->post_id]);\n        if ($updateNotify && $updateComment && $updateTopic) {\n            $transaction->commit();\n        } else {\n            $transaction->rollback();\n        }\n        return $this->redirect(['/topic/default/view', 'id' => $model->post_id]);\n    }\n\n}\n"
  },
  {
    "path": "frontend/modules/topic/controllers/DefaultController.php",
    "content": "<?php\n\nnamespace frontend\\modules\\topic\\controllers;\n\nuse common\\components\\Controller;\nuse common\\models\\PostComment;\nuse common\\models\\PostMeta;\nuse common\\models\\Search;\nuse common\\models\\SearchLog;\nuse common\\models\\User;\nuse common\\services\\PostService;\nuse common\\services\\TopicService;\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\user\\models\\Donate;\nuse Yii;\nuse yii\\data\\ActiveDataProvider;\nuse yii\\filters\\AccessControl;\nuse yii\\filters\\VerbFilter;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\Html;\nuse yii\\web\\NotFoundHttpException;\n\nclass DefaultController extends Controller\n{\n    /**\n     * @var integer 评论翻页\n     */\n    const PAGE_SIZE = 300;\n    public $sorts = [\n        'newest' => '最新',\n        'excellent' => '优质',\n        'hotest' => '热门',\n//        'uncommented' => '未回答的'\n    ];\n\n    public function behaviors()\n    {\n        return ArrayHelper::merge(parent::behaviors(), [\n            'verbs' => [\n                'class' => VerbFilter::className(),\n                'actions' => [\n                    'delete' => ['post'],\n                ],\n            ],\n            'access' => [\n                'class' => AccessControl::className(),\n                'rules' => [\n                    // 默认只能Get方式访问\n                    ['allow' => true, 'actions' => ['view', 'index', 'search', 'captcha'], 'verbs' => ['GET']],\n                    // 登录用户才能提交回复或其他内容\n                    ['allow' => true, 'actions' => ['api', 'view', 'delete'], 'verbs' => ['POST'], 'roles' => ['@']],\n                    // 登录用户才能使用API操作(赞,踩,收藏)\n                    ['allow' => true, 'actions' => ['create', 'update', 'revoke', 'excellent'], 'roles' => ['@']],\n                ]\n            ],\n        ]);\n    }\n\n\n    /**\n     * 话题列表\n     * @return mixed\n     */\n    public function actionIndex()\n    {\n        // 话题或者分类筛选\n        $params = Yii::$app->request->queryParams;\n        $search = PostService::search($params);\n\n        return $this->render('index', [\n            'searchModel' => $search['searchModel'],\n            'sorts' => $this->sorts,\n            'dataProvider' => $search['dataProvider'],\n            'nodes' => PostMeta::getNodes(),\n        ]);\n    }\n\n    public function actionSearch()\n    {\n        $keyword = htmlspecialchars(Yii::$app->request->get('keyword'));\n        if (empty($keyword)) {\n            $this->goHome();\n        }\n\n        // 记录log\n        $model = new SearchLog();\n        $model->setAttributes([\n            'user_id' => (Yii::$app->user->isGuest) ? '' : Yii::$app->user->identity->getId(),\n            'keyword' => $keyword,\n            'created_at' => time(),\n        ]);\n        $model->save();\n\n        $id = ArrayHelper::getColumn(Search::search($keyword), 'topic_id') ?: 0;\n        $search = PostService::search(['PostSearch' => ['id' => $id]]);\n\n        return $this->render('index', [\n            'searchModel' => $search['searchModel'],\n            'sorts' => $this->sorts,\n            'dataProvider' => $search['dataProvider'],\n        ]);\n    }\n\n    /**\n     * 话题详细页\n     * @param integer $id\n     * @return mixed\n     */\n    public function actionView($id)\n    {\n        $model = Topic::findTopic($id);\n\n        //登录才能访问的节点内容\n        if (\\Yii::$app->user->isGuest && in_array($model->category->alias, params('loginNode'))) {\n            $this->flash('查看本主题需要登录!', 'warning');\n            return $this->redirect(['/site/login']);\n        }\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => PostComment::findCommentList($id),\n            'pagination' => [\n                'pageSize' => self::PAGE_SIZE,\n            ],\n            'sort' => ['defaultOrder' => ['created_at' => SORT_ASC]]\n        ]);\n\n        // 文章浏览次数\n        Topic::updateAllCounters(['view_count' => 1], ['id' => $id]);\n\n        //内容页面打赏\n        if (in_array($model->category->alias, params('donateNode')) || array_intersect(explode(',', $model->tags),\n                params('donateTag'))) {\n            $donate = Donate::findOne(['user_id' => $model->user_id, 'status' => Donate::STATUS_ACTIVE]);\n        }\n\n        /** @var User $user */\n        $user = Yii::$app->user->identity;\n        $admin = ($user && ($user->isAdmin($user->username) || $user->isSuperAdmin($user->username))) ? true : false;\n\n        return $this->render('view', [\n            'model' => $model,\n            'dataProvider' => $dataProvider,\n            'comment' => new PostComment(),\n            'admin' => $admin,\n            'donate' => isset($donate) ? $donate : [],\n        ]);\n    }\n\n    /**\n     * 新建话题\n     * @return mixed\n     * @throws \\yii\\base\\ExitException\n     */\n    public function actionCreate()\n    {\n        $model = new Topic();\n        if ($time = $model->limitPostTime()) {\n            $this->flash(\"发表文章失败!新注册用户只能回帖，{$time}秒之后才能发帖。\", 'warning');\n            return $this->redirect('index');\n        }\n        if ($time = $model->limitPostingIntervalTime()) {\n            $this->flash(\"发表文章失败!请勿连续频繁发帖，{$time}秒之后才能发帖。\", 'warning');\n            return $this->redirect('index');\n        }\n        if ($model->load(Yii::$app->request->post()) && $model->validate()) {\n            $topService = new TopicService();\n            if (!$topService->filterContent($model->title) || !$topService->filterContent($model->content)) {\n                $model->addError('content', '请勿发表无意义的内容');\n                return $this->redirect('create');\n            }\n\n            if ($model->save(false)) {\n                $this->flash('发表文章成功!', 'success');\n                return $this->redirect(['view', 'id' => $model->id]);\n            }\n        } else {\n            return $this->render('create', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * 修改自己的话题\n     * @param integer $id\n     * @return string|\\yii\\web\\Response\n     * @throws NotFoundHttpException\n     * @throws \\yii\\base\\ExitException\n     */\n    public function actionUpdate($id)\n    {\n        $model = Topic::findTopic($id);\n\n        if (!($model && (User::getThrones() || $model->isCurrent()))) {\n            throw new NotFoundHttpException;\n        }\n\n        if ($model->load(Yii::$app->request->post()) && $model->validate()) {\n            if ($model->save()) {\n                $this->flash('发表更新成功!', 'success');\n                return $this->redirect(['view', 'id' => $model->id]);\n            }\n        } else {\n            return $this->render('update', [\n                'model' => $model,\n            ]);\n        }\n    }\n\n    /**\n     * 伪删除\n     * @param $id\n     * @return \\yii\\web\\Response\n     * @throws NotFoundHttpException\n     */\n    public function actionDelete($id)\n    {\n        $model = Topic::findTopic($id);\n        if (!($model && (User::getThrones() || $model->isCurrent()))) {\n            throw new NotFoundHttpException;\n        }\n\n        if ($model->comment_count) {\n            $this->flash(\"「{$model->title}」此文章已有回复，属于共有财产，不能删除\", 'warning');\n        } else {\n\n            TopicService::delete($model);\n            $revoke = Html::a('撤消', ['/topic/default/revoke', 'id' => $model->id]);\n            $this->flash(\"「{$model->title}」文章删除成功。 反悔了？{$revoke}\", 'success');\n        }\n\n        return $this->redirect(['index']);\n    }\n\n    /**\n     * 撤消删除\n     * @param $id\n     * @return \\yii\\web\\Response\n     * @throws NotFoundHttpException\n     */\n    public function actionRevoke($id)\n    {\n        $model = Topic::findDeletedTopic($id);\n        if (!($model && (User::getThrones() || $model->isCurrent()))) {\n            throw new NotFoundHttpException;\n        }\n        TopicService::revoke($model);\n        $this->flash(\"「{$model->title}」文章撤销删除成功。\", 'success');\n        return $this->redirect(['/topic/default/view', 'id' => $model->id]);\n    }\n\n    /**\n     * 加精华\n     * @param $id\n     * @return \\yii\\web\\Response\n     * @throws NotFoundHttpException\n     */\n    public function actionExcellent($id)\n    {\n        /** @var User $user */\n        $user = Yii::$app->user->identity;\n        $model = Topic::findTopic($id);\n        if ($user && ($user->isAdmin($user->username) || $user->isSuperAdmin($user->username))) {\n            TopicService::excellent($model);\n            $this->flash(\"操作成功\", 'success');\n            return $this->redirect(['/topic/default/view', 'id' => $model->id]);\n        } else {\n            throw new NotFoundHttpException();\n        }\n    }\n}\n"
  },
  {
    "path": "frontend/modules/topic/models/Topic.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午 5:57\n * description:\n */\n\nnamespace frontend\\modules\\topic\\models;\n\n\nuse common\\models\\Post;\nuse common\\models\\PostTag;\nuse common\\models\\Search;\nuse common\\models\\UserInfo;\nuse common\\services\\NotificationService;\nuse common\\services\\TopicService;\nuse frontend\\modules\\user\\models\\UserMeta;\nuse Yii;\nuse yii\\helpers\\Url;\nuse yii\\web\\NotFoundHttpException;\n\nclass Topic extends Post\n{\n    const TYPE = 'topic';\n\n    /**\n     * @var boolean CC 协议\n     */\n    public $cc;\n\n    public function getLike()\n    {\n        $model = new UserMeta();\n        return $model->isUserAction(self::TYPE, 'like', $this->id);\n    }\n\n    public function getFollow()\n    {\n        $model = new UserMeta();\n        return $model->isUserAction(self::TYPE, 'follow', $this->id);\n    }\n\n    public function getHate()\n    {\n        $model = new UserMeta();\n        return $model->isUserAction(self::TYPE, 'hate', $this->id);\n    }\n\n    public function getFavorite()\n    {\n        $model = new UserMeta();\n        return $model->isUserAction(self::TYPE, 'favorite', $this->id);\n    }\n\n    public function getThanks()\n    {\n        $model = new UserMeta();\n        return $model->isUserAction(self::TYPE, 'thanks', $this->id);\n    }\n\n    /**\n     * 获取关注者\n     */\n    public function getFollower()\n    {\n        return $this->hasMany(UserMeta::className(), ['target_id' => 'id'])\n            ->where(['target_type' => self::TYPE, 'type' => 'follow']);\n    }\n\n    /**\n     * 通过 ID 获取指定话题\n     * @param $id\n     * @param string $condition\n     * @return array|null|\\yii\\db\\ActiveRecord\n     * @throws NotFoundHttpException\n     */\n    public static function findModel($id, $condition = '')\n    {\n//        if (!($model = Yii::$app->cache->get('topic' . $id))) {\n        $model = static::find()\n            ->where($condition)\n            ->andWhere(['id' => $id, 'type' => self::TYPE])\n            ->one();\n//        }\n        if ($model) {\n//            Yii::$app->cache->set('topic' . $id, $model, 0);\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n\n    }\n\n    /**\n     * 通过 ID 获取指定话题\n     * @param $id\n     * @return array|Topic|null|\\yii\\db\\ActiveRecord\n     * @throws NotFoundHttpException\n     */\n    public static function findTopic($id)\n    {\n        return static::findModel($id, ['>=', 'status', self::STATUS_ACTIVE]);\n    }\n\n    /**\n     * 获取已经删除过的话题\n     * @param $id\n     * @return array|Topic|null|\\yii\\db\\ActiveRecord\n     * @throws NotFoundHttpException\n     */\n    public static function findDeletedTopic($id)\n    {\n        return static::findModel($id, ['>=', 'status', self::STATUS_DELETED]);\n    }\n\n    public $atUsers;\n\n    public function beforeSave($insert)\n    {\n        if (parent::beforeSave($insert)) {\n\n            if ($this->tags && is_array($this->tags)) {\n                $this->addTags($this->tags);\n                $this->tags = implode(',', $this->tags);\n            }\n            if (params('createPostNeedVerify')) {\n                $this->status = self::STATUS_DELETED;\n            }\n\n            $username = Yii::$app->user->identity->username;\n            $url = Url::to('/member/' . $username, true);\n            $this->content = TopicService::contentTopic($this->content, $this) .\n                ($this->cc ? t('app', 'cc {username} {url}', ['username' => $username, 'url' => $url]) : '');\n\n            if ($insert) {\n                $this->user_id = (($this->user_id) ?: Yii::$app->user->id);\n                $this->type = self::TYPE;\n                $this->last_comment_time = $this->created_at;\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public function afterSave($insert, $changedAttributes)\n    {\n        parent::afterSave($insert, $changedAttributes);\n        if (isset(Yii::$app->params['setting']) && Yii::$app->params['setting']['xunsearch']) {\n            if ($insert) {\n                $search = new Search();\n                $search->topic_id = $this->id;\n                $search->status = self::STATUS_ACTIVE;\n            } else {\n                $search = Search::findOne($this->id);\n                if (!$search) {\n                    // 如果立即修改 会因为在 xunsearch 找不到而不能 save\n                    return false;\n                }\n                $search->status = $this->status;\n            }\n            $search->title = $this->title;\n            $search->content = $this->content;\n            $search->updated_at = $this->updated_at;\n            $search->save();\n        }\n\n        (new NotificationService())->newPostNotify(\\Yii::$app->user->identity, $this, $this->atUsers);\n        if ($insert) {\n            // 保存 meta data\n            (new UserMeta)->saveNewMeta('topic', $this->id, 'follow');\n            // 更新个人总统计\n            UserInfo::updateAllCounters(['post_count' => 1], ['user_id' => $this->user_id]);\n        }\n    }\n\n    /**\n     * 最后回复更新\n     * @param string $username\n     * @return bool\n     */\n    public function lastCommentToUpdate($username = '')\n    {\n        $this->setAttributes([\n            'last_comment_username' => $username,\n            'last_comment_time' => time()\n        ]);\n        return $this->save();\n    }\n\n    /**\n     * 添加标签\n     * @param array $tags\n     * @return bool\n     */\n    public function addTags(array $tags)\n    {\n        $return = false;\n        $tagItem = new PostTag();\n        foreach ($tags as $tag) {\n            $_tagItem = clone $tagItem;\n            $tagRaw = $_tagItem::findOne(['name' => $tag]);\n            if (!$tagRaw) {\n                $_tagItem->setAttributes([\n                    'name' => $tag,\n                    'count' => 1,\n                ]);\n                if ($_tagItem->save()) {\n                    $return = true;\n                }\n            } else {\n                $tagRaw->updateCounters(['count' => 1]);\n            }\n        }\n        return $return;\n    }\n}"
  },
  {
    "path": "frontend/modules/topic/views/comment/_form.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/20 下午9:15\n * description:\n */\n\nuse common\\widgets\\JsBlock;\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Url;\nuse yii\\widgets\\ActiveForm;\nuse yiier\\editor\\EditorMdWidget;\n\n\\frontend\\assets\\AtJsAsset::register($this);\n?>\n<div class=\"list-group-item\">\n\n    <?php if (Yii::$app->user->isGuest): ?>\n        <div style=\"padding:20px;\" data-turbolinks-action=\"replace\">\n            需要 <a class=\"btn btn-primary\" href=\"<?= Url::to(['/site/login']) ?>\">登录</a> 后方可回复,\n            如果你还没有账号请点击这里 <a class=\"btn btn-danger\" href=\"<?= Url::to(['/site/signup']) ?>\">注册</a>。\n        </div>\n    <?php else: ?>\n\n    <?php $form = ActiveForm::begin([\n        'action' => [\n            $model->isNewRecord ? '/topic/comment/create' : '/topic/comment/update',\n            'id' => Yii::$app->request->getQueryParam('id')],\n        'fieldConfig' => [\n            'template' => \"{input}\\n{hint}\\n{error}\"\n        ]\n    ]); ?>\n\n    <?= $form->field($model, 'comment')->widget(EditorMdWidget::className(), [\n        'clientOptions' => [\t\n            'height' => 200,\t\n            'imageUpload' => true,\t\n            'autoFocus' => false,\n            'placeholder' => '请尽量让自己的回复能够对别人有帮助',\t\n            'imageUploadURL' => Url::to(['/site/upload', 'field' => 'editormd-image-file']),\t\n        ]\t\n    ]) ?>\n\n        <div class=\"form-group\">\n            <?= Html::submitButton(\n                $model->isNewRecord ? '创建回复' : '修改回复',\n                [\n                    'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary',\n                ]\n            ) ?>\n\n            <div class=\"pull-right\">\n                <?= Html::a('排版说明', ['/site/markdown'], ['target' => '_blank']) ?>\n            </div>\n        </div>\n\n    <?php ActiveForm::end(); ?>\n    <?php JsBlock::begin(['pos' => \\yii\\web\\View::POS_READY]) ?>\n        <script>\n            $(document).on('click', '.btn-reply', function (e) {\n                e.preventDefault();\n                var username = $(this).data('username');\n                var floor = $(this).data('floor');\n                var prefix = \"@\" + username + \" #\" + floor + \"楼 \";\n                editor.insertValue(prefix);\n                editor.focus();\n            });\n        </script>\n        <?php JsBlock::end() ?>\n    <?php endif ?>\n</div>\n"
  },
  {
    "path": "frontend/modules/topic/views/comment/_item.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/20 下午9:56\n * description:\n */\n\nuse yii\\helpers\\Html;\nuse yii\\helpers\\HtmlPurifier;\nuse yii\\helpers\\Markdown;\n\n/** @var \\common\\models\\PostComment $model */\n$index += +1 + $widget->dataProvider->pagination->page * $widget->dataProvider->pagination->pageSize;\n?>\n<?php if (!$model->status): ?>\n    <div class=\"deleted text-center\"><?= $index ?>楼 已删除.</div>\n<?php else: ?>\n    <div class=\"avatar pull-left\">\n        <?= Html::a(Html::img($model->user->userAvatar, ['class' => 'media-object avatar-48 img-circle']),\n            ['/user/default/show', 'username' => $model->user['username']]\n        ); ?>\n    </div>\n\n    <div class=\"infos\" id=\"comment<?= $index ?>\">\n\n        <div class=\"media-heading meta info opts\">\n            <?php\n            echo Html::a($model->user['username'], ['/user/default/show', 'username' => $model->user['username']], ['class' => 'author']), '•',\n            Html::a(\"#{$index}\", \"#comment{$index}\", ['class' => 'comment-floor']), '•',\n            Html::tag('addr', Yii::$app->formatter->asRelativeTime($model->created_at), ['title' => Yii::$app->formatter->asDatetime($model->created_at)]);\n            ?>\n\n            <span class=\"opts pull-right\">\n                <?php\n\n                if ($model->isCurrent()) {\n                    echo Html::a(\n                        Html::tag('i', '', ['class' => 'fa fa-thumbs-o-up']) . ' ' . Html::tag('span', $model->like_count) . ' 个赞',\n                        'javascript:;'\n                    );\n\n                    echo Html::a('',\n                        ['/topic/comment/update', 'id' => $model->id],\n                        ['title' => '修改回帖', 'class' => 'fa fa-pencil']\n                    );\n                    echo Html::a('',\n                        ['/topic/comment/delete', 'id' => $model->id],\n                        [\n                            'title' => '删除回复',\n                            'class' => 'fa fa-trash',\n                            'data' => [\n                                'confirm' => \"您确认要删除回复吗？\",\n                                'method' => 'post',\n                            ],\n                        ]\n                    );\n                } else {\n                    echo Html::a(\n                        Html::tag('i', '', ['class' => 'fa fa-thumbs-o-up']) . ' ' . Html::tag('span', $model->like_count) . ' 个赞',\n                        '#',\n                        [\n                            'data-do' => 'like',\n                            'data-id' => $model->id,\n                            'data-type' => 'comment',\n                            'class' => ($model->like) ? 'active' : ''\n                        ]\n                    );\n                    echo Html::a('', '#',\n                        [\n                            'data-username' => $model->user['username'],\n                            'data-floor' => $index,\n                            'title' => '回复此楼',\n                            'class' => 'fa fa-mail-reply btn-reply'\n                        ]\n                    );\n                }\n                ?>\n            </span>\n\n        </div>\n\n        <div class=\"media-body markdown-reply article\">\n            <?= HtmlPurifier::process(Markdown::process($model->comment, 'gfm')) ?>\n        </div>\n    </div>\n<?php endif ?>"
  },
  {
    "path": "frontend/modules/topic/views/comment/create.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/20 下午9:17\n * description:\n */\n\n?>\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading clearfix\">\n        添加回复 <?php if (Yii::$app->user->getIsGuest()): ?> <small class=\"text-warning\">(需要登录)</small> <?php endif ?>\n    </div>\n\n    <?= $this->render('_form', [\n        'model' => $model,\n    ]) ?>\n</div>"
  },
  {
    "path": "frontend/modules/topic/views/comment/index.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/20 下午9:16\n * description:\n */\nuse yii\\helpers\\Html;\n?>\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading clearfix\">\n        <?= \\Yii::t('app', 'Received {0} reply', $model->comment_count) ?>\n        <?php if ($tags = $model->tags): ?>\n            <span class=\"pull-right\">\n                <i class=\"icon-tags\"></i>\n                <?php foreach (explode(',', $tags) as $key => $value){\n                    echo Html::a(Html::encode($value),\n                        ['/topic/default/index', 'tag' => $value],\n                        ['class' => 'btn btn-xs btn-primary']\n                    ), ' ';} ?>\n            </span>\n        <?php endif ?>\n    </div>\n\n    <?= \\yii\\widgets\\ListView::widget([\n        'dataProvider' => $dataProvider,\n        'itemOptions' => ['class' => 'list-group-item media mt0'],\n        'summary' => false,\n        'itemView' => '_item',\n    ]) ?>\n</div>"
  },
  {
    "path": "frontend/modules/topic/views/comment/update.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/20 下午9:15\n * description:\n */\n\nuse yii\\helpers\\Html;\n\n/** @var \\common\\models\\PostComment $model */\n$this->title = Yii::t('app', '更新回复: ') . ' ' . $model->post->title;\n?>\n    <div class=\"col-md-9 topic-create\" contenteditable=\"false\" style=\"\">\n\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading clearfix\">\n                <?= '更新回复： ' . Html::a($model->post->title, ['/topic/default/view', 'id' => $model->post_id]) ?>\n            </div>\n\n            <?= $this->render('_form', [\n                'model' => $model,\n            ]) ?>\n        </div>\n    </div>\n\n<?= \\frontend\\widgets\\TopicSidebar::widget([]) ?>"
  },
  {
    "path": "frontend/modules/topic/views/default/_form.php",
    "content": "<?php\n\nuse common\\models\\PostTag;\nuse conquer\\select2\\Select2Widget;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Url;\nuse yii\\widgets\\ActiveForm;\nuse yiier\\editor\\EditorMdWidget;\n\n/** @var  $model \\frontend\\modules\\topic\\models\\Topic */\n$model->tags = $model->tags ? explode(',', $model->tags) : '';\n?>\n<div class=\"list-group-item\">\n\n    <?php $form = ActiveForm::begin([\n        'options' => [\n            'autocomplete' => 'off'\n        ],\n        'fieldConfig' => [\n            'template' => \"{input}\\n{hint}\\n{error}\"\n        ]\n    ]); ?>\n\n    <?= $form->errorSummary($model, [\n        'class' => 'alert alert-danger'\n    ]) ?>\n\n    <?= $form->field($model, 'title')->textInput([\n        'maxlength' => 255,\n        'placeholder' => '标题'\n    ]) ?>\n\n    <?= $form->field($model, 'post_meta_id')->widget(Select2Widget::classname(), [\n        'items' => ['' => '选择一个分类'] + \\common\\models\\PostMeta::topicCategory(),\n    ]); ?>\n\n    <?= $form->field($model, 'content')->widget(EditorMdWidget::className(), [\n        'options' => ['id' => 'sss'],\n        'clientOptions' => [\n            'placeholder' => '鼓励分享和讨论不鼓励伸手提问党。真的想提问请在提问帖内附上你曾经为了解决问题付出的行动或者分享一段小知识。',\n            'imageUpload' => true,\n            'autoFocus' => false,\n            'imageUploadURL' => Url::to(['/site/upload', 'field' => 'editormd-image-file']),\n        ]\n    ]) ?>\n\n    <?= $form->field($model, 'tags')->widget(Select2Widget::classname(), [\n        'options' => [\n            'multiple' => true,\n            'placeholder' => '标签（可选）'\n        ],\n        'settings' => ['width' => '100%'],\n        'items' => ArrayHelper::map(PostTag::find()->orderBy('count')->asArray()->all(), 'name', 'name'),\n    ]); ?>\n\n    <div class=\"form-group\">\n        <?= $form->field($model, 'cc')->checkbox() ?>\n    </div>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton(\n            $model->isNewRecord ? '创建话题' : '修改话题',\n            [\n                'class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary',\n            ]\n        ) ?>\n\n        <div class=\"pull-right\">\n            <?= Html::a('排版说明', ['/site/markdown'], ['target' => '_blank']) ?>\n        </div>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>\n<?php\n\\frontend\\assets\\AtJsAsset::register($this);\n?>\n"
  },
  {
    "path": "frontend/modules/topic/views/default/_item.php",
    "content": "<?php\n\nuse common\\helpers\\Formatter;\nuse frontend\\modules\\topic\\models\\Topic;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\Html;\n\n/* @var $this yii\\web\\View */\n/* @var  Topic $model */\n?>\n<div class=\"media\">\n    <?= Html::a(Html::tag('span', $model['comment_count'], ['class' => 'badge badge-reply-count']),\n        ['/topic/default/view', 'id' => $model->id, '#' => 'comment' . $model['comment_count']],\n        ['class' => 'pull-right']\n    ); ?>\n\n    <div class=\"media-left\">\n        <?= Html::a(Html::img(ArrayHelper::getValue($model->user, 'userAvatar'),\n            ['class' => 'media-object img-circle']),\n            ['/user/default/show', 'username' => $model->user['username']]\n        ); ?>\n    </div>\n    <div class=\"media-body\">\n\n        <div class=\"media-heading title\">\n            <?= Html::a(Html::encode($model->title),\n                ['/topic/default/view', 'id' => $model->id], ['title' => $model->title]\n            ); ?>\n            <?= ($model->status == Topic::STATUS_EXCELLENT) ? Html::tag('i', '',\n                ['class' => 'fa fa-trophy excellent']) : null ?>\n        </div>\n\n        <div class=\"title-info\">\n            <?php\n            if ($model->like_count) {\n                echo Html::a(Html::tag('span', ' ' . $model->like_count . ' ', ['class' => 'fa fa-thumbs-o-up']),\n                    ['/topic/default/view', 'id' => $model->id], ['class' => 'remove-padding-left']\n                ), ' • ';\n            }\n            if (!request('node') && isset($model->category->name)) {\n                echo Html::a(\n                    $model->category->name,\n                    ['/topic/default/index', 'node' => $model->category->alias],\n                    ['class' => 'node']\n                ), ' • ';\n            }\n\n            if ($model->last_comment_username) {\n                echo Html::tag('span',\n                    Yii::t('frontend', 'last_by') .\n                    Html::a(\n                        Html::tag('strong', ' ' . $model->last_comment_username . ' '),\n                        ['/user/default/show', 'username' => $model->last_comment_username]) .\n                    Yii::t('frontend', 'reply_at {datetime}', [\n                        'datetime' => Formatter::relative($model->last_comment_time)\n                    ])\n                );\n            } else {\n                echo '由',\n                Html::a(\n                    Html::tag('strong', ' ' . $model->user['username'] . ' '),\n                    ['/user/default/show', 'username' => $model->user['username']]\n                ),\n                Html::tag('span',\n                    Yii::t('frontend', 'created_at {datetime}', [\n                        'datetime' => Formatter::relative($model->created_at)\n                    ])\n                );\n            }\n            echo ' • ' . $model->view_count . ' 次阅读'\n            ?>\n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "frontend/modules/topic/views/default/create.php",
    "content": "<?php\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\Post */\n\n$this->title = '发布新话题';\n// $this->params['breadcrumbs'][] = ['label' => 'Posts', 'url' => ['index']];\n// $this->params['breadcrumbs'][] = $this->title;\n?>\n<div class=\"col-md-9 topic-create\" contenteditable=\"false\" style=\"\">\n\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading clearfix\">\n            <?= $this->title ?>\n        </div>\n\n        <?= $this->render('_form', [\n            'model' => $model,\n        ]) ?>\n    </div>\n</div>\n\n<?= \\frontend\\widgets\\TopicSidebar::widget([\n    'type' => 'create'\n])?>"
  },
  {
    "path": "frontend/modules/topic/views/default/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Url;\nuse yii\\widgets\\ListView;\nuse yii\\widgets\\Pjax;\nuse frontend\\widgets\\TopicSidebar;\n\n$this->title = '社区';\n$sort = Yii::$app->request->getQueryParam('sort');\nif ($node = Yii::$app->request->getQueryParam('node')) {\n    $node = \\common\\models\\PostMeta::find()->where(['alias' => $node])->one();\n}\n/** @var array $sorts */\n/** @var \\common\\models\\PostMeta $node */\n/** @var \\common\\models\\PostMeta[] $nodes */\n/** @var \\yii\\data\\ActiveDataProvider $dataProvider */\n?>\n<div class=\"col-md-9 topic\">\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading clearfix tab\">\n            <?php if (request('node')): ?>\n                <div class=\"node-header\">\n                    <div class=\"title\">\n                        <?= $node->name ?>\n                        <span class=\"total\">共有 <?= $dataProvider->getTotalCount() ?> 个讨论主题</span>\n                    </div>\n                    <div class=\"summary\" id=\"node-summary\">\n                        <p><?= $node->description ?></p>\n                    </div>\n                </div>\n            <?php else: ?>\n                <span><?= Html::a('全部', ['/topic/default/index'], ['class' => request('tab') ? null : 'active']) ?></span>\n                <?php foreach ((array)$nodes as $key => $value): ?>\n                    <span><?= Html::a($value->name, ['/topic/default/index', 'tab' => $value->alias], ['class' => request('tab') == $value->alias ? 'active' : null]) ?></span>\n                <?php endforeach ?>\n            <?php endif ?>\n        </div>\n        <div class=\"panel-heading clearfix children\">\n            <div class=\"filter pull-right\">\n                <span class=\"l\">排序:</span>\n                <?php foreach ($sorts as $key => $name): ?>\n                    <?= Html::a($name, Url::current(['sort' => $key]), ['class' => ($sort == $key || ((empty($sort) && $key == 'newest'))) ? 'active' : '']) ?> \\\n                <?php endforeach ?>\n            </div>\n\n            <?php if (request('tag')) {\n                echo Html::tag('div', '搜索标签：' . htmlspecialchars(request('tag')), ['class' => 'pull-left']);\n            } elseif (request('keyword')) {\n                echo Html::tag('div', '搜索：' . htmlspecialchars(request('keyword')), ['class' => 'pull-left']);\n            } elseif (request('tab')) {\n                /** @var \\common\\models\\PostMeta $node */\n                if ($node = \\yii\\helpers\\ArrayHelper::getValue($nodes, request('tab'))) {\n                    foreach ($node->children as $item) {\n                        $active = request('node') == $item->alias ? 'active' : null;\n                        echo Html::a($item->name, ['/topic/default/index', 'node' => $item->alias], ['class' => \"children-node \" . $active]);\n                    }\n                }\n            } ?>\n\n        </div>\n\n\n        <?php Pjax::begin([\n            'scrollTo' => 0,\n            'formSelector' => false,\n            'linkSelector' => '.pagination a'\n        ]); ?>\n        <?= ListView::widget([\n            'dataProvider' => $dataProvider,\n            'itemOptions' => ['class' => 'list-group-item'],\n            'summary' => false,\n            'itemView' => '_item',\n            'options' => ['class' => 'list-group'],\n        ]) ?>\n        <?php Pjax::end(); ?>\n\n    </div>\n    <?= \\frontend\\widgets\\Node::widget(); ?>\n</div>\n<?= TopicSidebar::widget([\n    'node' => $node\n]); ?>\n\n"
  },
  {
    "path": "frontend/modules/topic/views/default/update.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\Post */\n\n$this->title =  Yii::t('app', 'Update Post: ') . ' ' . $model->title;\n?>\n<div class=\"col-md-9 topic-create\" contenteditable=\"false\" style=\"\">\n\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading clearfix\">\n            <?= Html::encode($this->title) ?>\n        </div>\n\n        <?= $this->render('_form', [\n            'model' => $model,\n        ]) ?>\n    </div>\n</div>\n\n<?= \\frontend\\widgets\\TopicSidebar::widget([\n    'type' => 'create'\n])?>"
  },
  {
    "path": "frontend/modules/topic/views/default/view.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\helpers\\HtmlPurifier;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\Models\\Post */\n/* @var $donate array|\\frontend\\modules\\user\\models\\Donate */\n\n$this->title = $model->title;\n\n?>\n\n    <div class=\"col-md-9 topic-view\" contenteditable=\"false\" style=\"\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading media clearfix\">\n                <div class=\"media-body\">\n                    <?= Html::tag('h1', Html::encode($model->title), ['class' => 'media-heading']); ?>\n                    <div class=\"info\">\n                        <?= Html::a(\n                            $model->category->name,\n                            ['/topic/default/index', 'node' => $model->category->alias],\n                            ['class' => 'node']\n                        ) ?>\n                        ·\n                        <?= Html::a($model->user['username'], ['/user/default/show', 'username' => $model->user['username']]) ?>\n                        ·\n                        于 <?= Html::tag('abbr', Yii::$app->formatter->asRelativeTime($model->created_at), ['title' => Yii::$app->formatter->asDatetime($model->created_at)]) ?>\n                        发布\n                        ·\n                        <?= $model->view_count ?> 次阅读\n                    </div>\n                </div>\n                <div class=\"avatar media-right\">\n                    <?= Html::a(Html::img($model->user->userAvatar, ['class' => 'media-object avatar-48 img-circle']),\n                        ['/user/default/show', 'username' => $model->user['username']]\n                    ); ?>\n                </div>\n            </div>\n            <div class=\"panel-body article\">\n                <?= HtmlPurifier::process(Markdown::process($model->content, 'gfm')) ?>\n\n                <?php if ($donate): ?>\n                    <hr/>\n                    <div style=\"text-align: center; color: #666;\">\n                        <?= Html::button('打赏作者', ['class' => 'btn btn-danger', 'id' => 'donate-btn']) ?>\n                        <p></p>\n                        <p><?= $donate->description ?></p>\n                        <div class=\"row\" id=\"donate-qr-code\">\n                            <div class=\"col-md-3\"></div>\n                            <div class=\"col-md-6\">\n                                <div class=\"panel panel-default corner-radius mt15\">\n                                    <div class=\"panel-body donate\">\n                                        <?= Html::img(params('qrCodeUrl') . '/' . $donate->qr_code, ['class' => 'img']) ?>\n                                    </div>\n                                </div>\n                                <div class=\"col-md-3\"></div>\n                            </div>\n                        </div>\n                    </div>\n                <?php endif ?>\n\n                <?php if ($model->status == 2): ?>\n                    <div class=\"ribbon-excellent\">\n                        <i class=\"fa fa-trophy excellent\"></i> 本帖已被设为精华帖！\n                    </div>\n                <?php endif ?>\n            </div>\n            <div class=\"panel-footer clearfix opts\">\n                <?php\n                $like = Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-thumbs-o-up']) . ' ' . Html::tag('span', $model->like_count) . ' 个赞',\n                    '#',\n                    [\n                        'data-do' => 'like',\n                        'data-id' => $model->id,\n                        'data-type' => $model->type,\n                        'class' => ($model->like) ? 'active' : ''\n                    ]\n                );\n                $hate = Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-thumbs-o-down']) . ' 踩',\n                    '#',\n                    [\n                        'data-do' => 'hate',\n                        'data-id' => $model->id,\n                        'data-type' => $model->type,\n                        'class' => ($model->hate) ? 'active' : ''\n                    ]\n                );\n                $follow = Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-eye']) . ' 关注',\n                    '#',\n                    [\n                        'data-do' => 'follow',\n                        'data-id' => $model->id,\n                        'data-type' => $model->type,\n                        'class' => ($model->follow) ? 'active' : ''\n                    ]\n                );\n                $thanks = Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-heart-o']) . ' 感谢',\n                    '#',\n                    [\n                        'data-do' => 'thanks',\n                        'data-id' => $model->id,\n                        'data-type' => $model->type,\n                        'class' => ($model->thanks) ? 'active' : ''\n                    ]\n                );\n                $favorite = Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-bookmark']) . ' 收藏',\n                    '#',\n                    [\n                        'data-do' => 'favorite',\n                        'data-id' => $model->id,\n                        'data-type' => $model->type,\n                        'class' => ($model->favorite) ? 'active' : ''\n                    ]\n                );\n\n                if ($model->isCurrent()) {\n                    echo Html::a(\n                        Html::tag('i', '', ['class' => 'fa fa-thumbs-o-up']) . ' ' . Html::tag('span', $model->like_count) . ' 个赞',\n                        'javascript:;'\n                    );\n                } else {\n                    echo $like, $hate;\n                    echo $thanks;\n                }\n                echo $follow;\n                echo $favorite;\n\n                if ($admin) {\n                    $class = $model->status == 2 ? ['class' => 'active'] : null;\n                    echo Html::a(\n                        Html::tag('i', '', ['class' => 'fa fa-trophy']) . ' 加精',\n                        ['/topic/default/excellent', 'id' => $model->id],\n                        $class\n                    );\n                }\n                ?>\n                <?php if ($model->isCurrent() || \\common\\models\\User::getThrones()): ?>\n                    <span class=\"pull-right\">\n                    <?= Html::a(\n                        Html::tag('i', '', ['class' => 'fa fa-pencil']) . ' 修改',\n                        ['/topic/default/update', 'id' => $model->id]\n                    ) ?>\n                    <?php if ($model->comment_count == 0): ?>\n                        <?= Html::a(\n                            Html::tag('i', '', ['class' => 'fa fa-trash']) . ' 删除',\n                            ['/topic/default/delete', 'id' => $model->id],\n                            [\n                                'data' => [\n                                    'confirm' => \"您确认要删除文章「{$model->title}」吗？\",\n                                    'method' => 'post',\n                                ],\n                            ]\n                        ) ?>\n                    <?php endif ?>\n                </span>\n                <?php endif ?>\n\n            </div>\n        </div>\n\n        <?= $this->render(\n            '@frontend/modules/topic/views/comment/index',\n            ['model' => $model, 'dataProvider' => $dataProvider]\n        ) ?>\n\n        <?= $this->render(\n            '@frontend/modules/topic/views/comment/create',\n            ['model' => $comment, 'post' => $model]\n        ) ?>\n\n    </div>\n<?= \\frontend\\widgets\\TopicSidebar::widget([\n    'type' => 'view',\n    'node' => $model->category,\n    'tags' => $model->tags\n]); ?>"
  },
  {
    "path": "frontend/modules/tweet/Module.php",
    "content": "<?php\n\nnamespace frontend\\modules\\tweet;\n\nclass Module extends \\yii\\base\\Module\n{\n    public $controllerNamespace = 'frontend\\modules\\tweet\\controllers';\n\n    public function init()\n    {\n        parent::init();\n\n        // custom initialization code goes here\n    }\n}\n"
  },
  {
    "path": "frontend/modules/tweet/controllers/DefaultController.php",
    "content": "<?php\n\nnamespace frontend\\modules\\tweet\\controllers;\n\nuse common\\components\\Controller;\nuse common\\models\\Post;\nuse common\\services\\TweetService;\nuse frontend\\modules\\tweet\\models\\Tweet;\nuse frontend\\modules\\tweet\\models\\TweetSearch;\nuse Yii;\nuse yii\\filters\\AccessControl;\nuse yii\\filters\\VerbFilter;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\web\\NotFoundHttpException;\n\nclass DefaultController extends Controller\n{\n    public function behaviors()\n    {\n        return ArrayHelper::merge(parent::behaviors(), [\n            'verbs' => [\n                'class' => VerbFilter::className(),\n                'actions' => [\n                    'delete' => ['post'],\n                ],\n            ],\n            'access' => [\n                'class' => AccessControl::className(),\n                'rules' => [\n                    // 默认只能Get方式访问\n                    ['allow' => true, 'actions' => ['index'], 'verbs' => ['GET']],\n                    // 登录用户POST操作\n                    ['allow' => true, 'actions' => ['delete'], 'verbs' => ['POST'], 'roles' => ['@']],\n                    // 登录用户才能操作\n                    ['allow' => true, 'actions' => ['create'], 'roles' => ['@']],\n                ]\n            ],\n        ]);\n    }\n\n    /**\n     * @return string\n     * @throws \\yii\\base\\ExitException\n     */\n    public function actionIndex()\n    {\n        $searchModel = new TweetSearch();\n        $params = Yii::$app->request->queryParams;\n        $params['TweetSearch']['content'] = empty($params['topic']) ? '' : $params['topic'];\n        $dataProvider = $searchModel->search($params);\n        $dataProvider->query->andWhere([\n            Post::tableName() . '.type' => Tweet::TYPE,\n            'status' => [Post::STATUS_ACTIVE, Post::STATUS_EXCELLENT]\n        ]);\n\n        $model = new Tweet();\n\n        if ($time = $model->limitPostTime()) {\n            $this->flash(\"新注册用户只能回帖，{$time}秒之后才能发帖。\", 'warning');\n        }\n\n        return $this->render('index', [\n            'model' => $model,\n            'searchModel' => $searchModel,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * 新建动弹\n     * @return mixed\n     * @throws \\yii\\base\\ExitException\n     */\n    public function actionCreate()\n    {\n        $model = new Tweet();\n\n        if ($model->load(Yii::$app->request->post()) && $model->validate()) {\n            $topService = new TweetService();\n            if (!$topService->filterContent($model->content)) {\n                $model->addError('content', '请勿发表无意义的内容');\n                return $this->redirect('index');\n            }\n            $model->user_id = Yii::$app->user->id;\n            $model->type = $model::TYPE;\n            if ($model->save()) {\n                $this->flash('发表成功!', 'success');\n            }\n        }\n        if ($model->hasErrors()) {\n            $this->flash('发表失败!' . array_values($model->firstErrors)[0], 'error');\n        }\n        return $this->redirect('index');\n    }\n\n    /**\n     * 伪删除\n     * @param $id\n     * @return \\yii\\web\\Response\n     * @throws NotFoundHttpException\n     * @throws \\yii\\base\\ExitException\n     */\n    public function actionDelete($id)\n    {\n        /** @var Tweet $model */\n        $model = Tweet::findTweet($id);\n        if (!$model->isCurrent()) {\n            throw new NotFoundHttpException();\n        }\n        if ($model->comment_count) {\n            $model->addError('content', '已有回复，属于共有财产，不能删除');\n        } else {\n            TweetService::delete($model);\n            $this->flash(\"删除成功。 \", 'success');\n        }\n\n        return $this->redirect(['index']);\n    }\n}\n"
  },
  {
    "path": "frontend/modules/tweet/models/Tweet.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午5:57\n * description:\n */\n\nnamespace frontend\\modules\\tweet\\models;\n\nuse common\\models\\Post;\nuse common\\services\\NotificationService;\nuse common\\services\\PostService;\nuse frontend\\modules\\user\\models\\UserMeta;\nuse Yii;\nuse yii\\web\\NotFoundHttpException;\n\nclass Tweet extends Post\n{\n    const TYPE = 'tweet';\n\n    public function getLike()\n    {\n        $model = new UserMeta();\n        return $model->isUserAction(self::TYPE, 'like', $this->id);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['content'], 'required'],\n            ['content', 'validateLimitPostTime'],\n            [\n                [\n                    'post_meta_id',\n                    'user_id',\n                    'view_count',\n                    'comment_count',\n                    'favorite_count',\n                    'like_count',\n                    'thanks_count',\n                    'hate_count',\n                    'status',\n                    'order',\n                    'created_at',\n                    'updated_at'\n                ],\n                'integer'\n            ],\n            [['content'], 'string', 'min' => 3, 'max' => 500],\n            [['post_meta_id'], 'default', 'value' => 0],\n            [['title'], 'default', 'value' => ''],\n        ];\n    }\n\n    /**\n     * 通过ID获取指定话题\n     * @param $id\n     * @param string $condition\n     * @return array|null|\\yii\\db\\ActiveRecord|static\n     * @throws NotFoundHttpException\n     */\n    public static function findModel($id, $condition = '')\n    {\n        if (!$model = Yii::$app->cache->get('topic' . $id)) {\n            $model = static::find()\n                ->where($condition)\n                ->andWhere(['id' => $id, 'type' => self::TYPE])\n                ->one();\n        }\n        if ($model) {\n            Yii::$app->cache->set('topic' . $id, $model, 0);\n            return $model;\n        } else {\n            throw new NotFoundHttpException('The requested page does not exist.');\n        }\n    }\n\n\n    /**\n     * 通过ID获取指定动弹\n     * @param $id\n     * @return array|Topic|null|\\yii\\db\\ActiveRecord\n     * @throws NotFoundHttpException\n     */\n    public static function findTweet($id)\n    {\n        return static::findModel($id, ['>=', 'status', self::STATUS_ACTIVE]);\n    }\n\n    /**\n     * 获取已经删除过的动弹\n     * @param $id\n     * @return array|null|\\yii\\db\\ActiveRecord\n     * @throws NotFoundHttpException\n     */\n    public static function findDeletedTweet($id)\n    {\n        return static::findModel($id, ['>=', 'status', self::STATUS_DELETED]);\n    }\n\n    public $atUsers;\n\n    public function beforeSave($insert)\n    {\n        if (!parent::beforeSave($insert)) {\n            return false;\n        }\n\n        $this->content = PostService::contentTweet($this->content, $this);\n        return true;\n    }\n\n    public function afterSave($insert, $changedAttributes)\n    {\n        parent::afterSave($insert, $changedAttributes);\n\n        (new UserMeta())->saveNewMeta($this->type, $this->id, 'follow');\n        (new NotificationService())->newPostNotify(\\Yii::$app->user->identity, $this, $this->atUsers);\n    }\n\n}"
  },
  {
    "path": "frontend/modules/tweet/models/TweetSearch.php",
    "content": "<?php\n\nnamespace frontend\\modules\\tweet\\models;\n\nuse Yii;\nuse yii\\base\\Model;\nuse yii\\data\\ActiveDataProvider;\nuse common\\models\\Post;\n\n/**\n * PostSearch represents the model behind the search form about `common\\Models\\Post`.\n */\nclass TweetSearch extends Tweet\n{\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['id', 'post_meta_id', 'user_id', 'view_count', 'comment_count', 'favorite_count', 'like_count', 'thanks_count', 'hate_count', 'status', 'order', 'created_at', 'updated_at'], 'integer'],\n            [['type', 'title', 'author', 'excerpt', 'image', 'content', 'tags'], 'safe'],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function scenarios()\n    {\n        // bypass scenarios() implementation in the parent class\n        return Model::scenarios();\n    }\n\n    /**\n     * @param $params\n     * @return ActiveDataProvider\n     */\n    public function search($params)\n    {\n        $query = Tweet::find()->with('user');\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => $query,\n            'pagination' => [\n                'pageSize' => 20,\n            ],\n            'sort' => ['defaultOrder' => [\n                'order' => SORT_ASC,\n                'updated_at' => SORT_DESC,\n            ]]\n        ]);\n\n        if (!($this->load($params) && $this->validate())) {\n            return $dataProvider;\n        }\n\n        $query->andFilterWhere([\n            'id' => $this->id,\n            'post_meta_id' => $this->post_meta_id,\n            'user_id' => $this->user_id,\n            'view_count' => $this->view_count,\n            'comment_count' => $this->comment_count,\n            'favorite_count' => $this->favorite_count,\n            'like_count' => $this->like_count,\n            'thanks_count' => $this->thanks_count,\n            'hate_count' => $this->hate_count,\n            'status' => $this->status,\n            'order' => $this->order,\n            'created_at' => $this->created_at,\n            'updated_at' => $this->updated_at,\n        ]);\n\n        $query->andFilterWhere(['like', 'type', $this->type])\n            ->andFilterWhere(['like', 'title', $this->title])\n            ->andFilterWhere(['like', 'author', $this->author])\n            ->andFilterWhere(['like', 'excerpt', $this->excerpt])\n            ->andFilterWhere(['like', 'image', $this->image])\n            ->andFilterWhere(['like', 'content', $this->content])\n            ->andFilterWhere(['like', 'tags', $this->tags]);\n\n        return $dataProvider;\n    }\n}\n"
  },
  {
    "path": "frontend/modules/tweet/views/default/_form.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n\\frontend\\assets\\AtJsAsset::register($this);\n?>\n<div class=\"list-group-item\">\n\n    <?php $form = ActiveForm::begin([\n        'action' => '/tweet/default/create',\n        'fieldConfig' => [\n            'template' => \"{input}\\n{hint}\\n{error}\"\n        ]\n    ]); ?>\n\n    <?= $form->field($model, 'content', [\n        'selectors' => [\n            'input' => '#md-input'\n        ],\n    ])->textarea([\n        'placeholder' => t('app', 'Tweet Content'),\n        'id' => 'md-input',\n        'data-at-topic' => true,\n        'rows' => 5\n    ]) ?>\n\n    <div class=\"form-group\">\n        <?= Html::submitButton('发布', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>\n        <div class=\"pull-right\">\n            <?= Html::a('排版说明', ['/site/markdown'], ['target' => '_blank']) ?>\n        </div>\n    </div>\n\n    <?php ActiveForm::end(); ?>\n\n</div>"
  },
  {
    "path": "frontend/modules/tweet/views/default/_item.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\n\n/* @var $this yii\\web\\View */\n?>\n<div class=\"media\">\n\n    <div class=\"media-left\">\n        <?= Html::a(Html::img($model->user->userAvatar, ['class' => 'media-object']),\n            ['/user/default/show', 'username' => $model->user['username']]\n        ); ?>\n    </div>\n    <div class=\"media-body\">\n        <div class=\"fade-info\">\n            <?= Html::a(\n                $model->user['username'],\n                ['/user/default/show', 'username' => $model->user['username']]\n            ), '•',\n            Html::tag('span', \\common\\helpers\\Formatter::relative($model->updated_at));\n            ?>\n        </div>\n\n        <div class=\"media-heading\">\n            <?= \\yii\\helpers\\HtmlPurifier::process(\\yii\\helpers\\Markdown::process($model->content, 'gfm')) ?>\n        </div>\n\n        <div class=\"title-info pull-right\">\n            <?php if ($model->isCurrent()) {\n                echo Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-thumbs-o-up']) . ' ' . Html::tag('span', $model->like_count . ' '),\n                    'javascript:;'\n                );\n                if ($model->comment_count == 0) {\n                    echo Html::a(\n                        Html::tag('i', '', ['class' => 'fa fa-trash']) . ' 删除',\n                        ['/tweet/default/delete', 'id' => $model->id],\n                        [\n                            'data' => [\n                                'confirm' => \"您确认要删除吗？\",\n                                'method' => 'post',\n                            ],\n                        ]\n                    );\n                }\n            } else {\n                echo Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-thumbs-o-up']) . ' ' . Html::tag('span', $model->like_count . ' '),\n                    '#',\n                    [\n                        'data-do' => 'like',\n                        'data-id' => $model->id,\n                        'data-type' => $model->type,\n                        'class' => ($model->like) ? 'active' : ''\n                    ]\n                );\n            } ?>\n\n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "frontend/modules/tweet/views/default/index.php",
    "content": "<?php\n$this->title = '发布新动弹';\n/** @var \\frontend\\modules\\tweet\\models\\Tweet $model*/\n/** @var \\yii\\data\\ActiveDataProvider $dataProvider*/\n?>\n    <div class=\"col-md-9 tweet\" contenteditable=\"false\" style=\"\">\n\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading clearfix\">\n                <?= $this->title ?>\n                <span class=\"pull-right fade-info\" id=\"remaining\">500</span>\n            </div>\n\n            <?= $this->render('_form', [\n                'model' => $model,\n            ]) ?>\n        </div>\n        <?= \\yii\\widgets\\ListView::widget([\n            'dataProvider' => $dataProvider,\n            'itemView' => '_item',\n            'itemOptions' => ['class' => 'list-group-item item'],\n            'summary' => false,\n//            'options' => ['class' => ''],\n            'pager' => [\n                'class' => \\kop\\y2sp\\ScrollPager::className(),\n                'eventOnRendered' => \"function() {\n                    emojify.run();\n                    $('pre code').each(function (i, block) {\n                        hljs.highlightBlock(block);\n                    });\n                }\",\n                'triggerOffset' => 5\n            ]\n        ]); ?>\n    </div>\n\n<?= \\frontend\\widgets\\TopicSidebar::widget([\n    'type' => 'create'\n]) ?>\n"
  },
  {
    "path": "frontend/modules/user/Module.php",
    "content": "<?php\n\nnamespace frontend\\modules\\user;\n\nuse yii\\base\\Module as BaseModule;\n\nclass Module extends BaseModule\n{\n\tpublic $modelMap = [];\n\t/** @var bool Whether to show flash messages. */\n    public $enableFlashMessages = true;\n\n    public $controllerNamespace = 'frontend\\modules\\user\\controllers';\n\n    public function init()\n    {\n        parent::init();\n\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/controllers/ActionController.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/19 下午3:11\n * description:\n */\n\nnamespace frontend\\modules\\user\\controllers;\n\nuse common\\services\\CommentService;\nuse common\\services\\TopicService;\nuse common\\services\\TweetService;\nuse Yii;\nuse common\\components\\Controller;\nuse yii\\web\\NotFoundHttpException;\n\nclass ActionController extends Controller\n{\n    public function beforeAction($action)\n    {\n        if (Yii::$app->user->isGuest) {\n            Yii::$app->getResponse()->redirect(\\Yii::$app->getUser()->loginUrl)->send();\n        }\n        return parent::beforeAction($action);\n    }\n\n    /**\n     * 赞话题和回复\n     * @param $type\n     * @param $id\n     * @return array|string\n     * @throws NotFoundHttpException\n     */\n    public function actionLike($type, $id)\n    {\n        switch ($type) {\n            case 'topic':\n                $topicService = new TopicService();\n                list($result, $data) = $topicService->userDoAction($id, 'like');\n                break;\n            case 'tweet':\n                $tweetService = new TweetService();\n                list($result, $data) = $tweetService->userDoAction($id, 'like');\n                break;\n\n            case 'comment':\n                $commentService = new CommentService();\n                list($result, $data) = $commentService->userDoAction($id, 'like');\n                break;\n\n            default:\n                throw new NotFoundHttpException();\n                break;\n        }\n\n        if ($result) {\n            return $this->message('提交成功!', 'success');\n        } else {\n            return $this->message($data ? $data->getErrors() : '提交失败!');\n        }\n    }\n\n    /**\n     * 喝倒彩话题\n     * @param $type\n     * @param $id\n     * @return array|string\n     */\n    public function actionHate($type, $id)\n    {\n        if ($type == 'topic') {\n            $topicService = new TopicService();\n            list($result, $data) = $topicService->userDoAction($id, 'hate');\n\n            if ($result) {\n                return $this->message('提交成功!', 'success');\n            } else {\n                return $this->message($data ? $data->getErrors() : '提交失败!');\n            }\n        }\n    }\n\n    /**\n     * 关注话题\n     * @param $type\n     * @param $id\n     * @return array|string\n     */\n    public function actionFollow($type, $id)\n    {\n        if ($type == 'topic') {\n            $topicService = new TopicService();\n            list($result, $data) = $topicService->userDoAction($id, 'follow');\n\n            if ($result) {\n                return $this->message('提交成功!', 'success');\n            } else {\n                return $this->message($data ? $data->getErrors() : '提交失败!');\n            }\n        }\n    }\n\n    /**\n     * 感谢话题\n     * @param $type\n     * @param $id\n     * @return array|string\n     */\n    public function actionThanks($type, $id)\n    {\n        if ($type == 'topic') {\n            $topicService = new TopicService();\n            list($result, $data) = $topicService->userDoAction($id, 'thanks');\n\n            if ($result) {\n                return $this->message('提交成功!', 'success');\n            } else {\n                return $this->message($data ? $data->getErrors() : '提交失败!');\n            }\n        }\n    }\n\n    /**\n     * 收藏话题\n     * @param $type\n     * @param $id\n     * @return array|string\n     */\n    public function actionFavorite($type, $id)\n    {\n        if ($type == 'topic') {\n            $topicService = new TopicService();\n            list($result, $data) = $topicService->userDoAction($id, 'favorite');\n\n            if ($result) {\n                return $this->message('提交成功!', 'success');\n            } else {\n                return $this->message($data ? $data->getErrors() : '提交失败!');\n            }\n        }\n    }\n}"
  },
  {
    "path": "frontend/modules/user/controllers/DefaultController.php",
    "content": "<?php\n\nnamespace frontend\\modules\\user\\controllers;\n\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\user\\models\\UserMeta;\nuse common\\components\\Controller;\nuse common\\models\\User;\nuse common\\models\\UserInfo;\nuse common\\models\\PostComment;\nuse yii\\data\\ActiveDataProvider;\nuse yii\\web\\NotFoundHttpException;\nuse yiier\\merit\\models\\MeritLog;\n\nclass DefaultController extends Controller\n{\n    public function actionIndex()\n    {\n        return $this->redirect(['show', 'username' => \\Yii::$app->user->identity->username]);\n    }\n\n    /**\n     * Shows user's profile.\n     * @param  string $username\n     * @return \\yii\\web\\Response\n     * @throws \\yii\\web\\NotFoundHttpException\n     */\n    public function actionShow($username = '')\n    {\n        $user = $this->user($username);\n        // 个人主页浏览次数\n        $currentUserId = \\Yii::$app->getUser()->getId();\n        if (null != $currentUserId\n            && $user->id != $currentUserId\n        ) {\n            UserInfo::updateAllCounters(['view_count' => 1], ['user_id' => $user->id]);\n        }\n\n        return $this->render('show', [\n            'user' => $user,\n            'dataProvider' => $this->comment($user->id),\n        ]);\n    }\n\n    protected function comment($userId)\n    {\n        return new ActiveDataProvider([\n            'query' => PostComment::find()->where(['user_id' => $userId, 'status' => 1])->orderBy(['created_at' => SORT_DESC]),\n        ]);\n    }\n\n    /**\n     * 最近主题\n     * @param string $username\n     * @return string\n     * @throws NotFoundHttpException\n     */\n    public function actionPost($username = '')\n    {\n        $user = $this->user($username);\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => Topic::find()\n                ->where(['user_id' => $user->id, 'type' => Topic::TYPE])\n                ->andWhere('status > :status ', [':status' => Topic::STATUS_DELETED])\n                ->orderBy(['created_at' => SORT_DESC]),\n        ]);\n\n        return $this->render('show', [\n            'user' => $user,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * 最新收藏\n     * @param string $username\n     * @return string\n     * @throws NotFoundHttpException\n     */\n    public function actionFavorite($username = '')\n    {\n        $user = $this->user($username);\n\n        return $this->render('show', [\n            'user' => $user,\n            'dataProvider' => $this->userMeta($user->id, 'favorite'),\n        ]);\n    }\n\n    public function actionPoint($username = '')\n    {\n        $user = $this->user($username);\n\n        $dataProvider = new ActiveDataProvider([\n            'query' => MeritLog::find()->where([\n                'user_id' => $user->id,\n                'type' => 1,\n            ])->orderBy(['created_at' => SORT_DESC])\n        ]);\n\n        return $this->render('show', [\n            'user' => $user,\n            'dataProvider' => $dataProvider,\n        ]);\n    }\n\n    /**\n     * @param $username\n     * @return string\n     */\n    public function actionLike($username)\n    {\n        $user = $this->user($username);\n\n        return $this->render('show', [\n            'user' => $user,\n            'dataProvider' => $this->userMeta($user->id, 'like'),\n        ]);\n    }\n\n    /**\n     * @param $userId\n     * @param $type\n     * @param string $targetType\n     * @return ActiveDataProvider\n     */\n    protected function userMeta($userId, $type, $targetType = 'topic')\n    {\n        return new ActiveDataProvider([\n            'query' => UserMeta::find()->where([\n                'user_id' => $userId,\n                'type' => $type,\n                'target_type' => $targetType,\n            ])->orderBy(['created_at' => SORT_DESC])\n        ]);\n    }\n\n\n    protected function user($username = '')\n    {\n        $user = User::findOne(['username' => $username]);\n\n        if ($user === null) {\n            throw new NotFoundHttpException;\n        }\n        return $user;\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/controllers/SecurityController.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-24 22:21:45\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-04-12 12:24:48\n */\n\nnamespace frontend\\modules\\user\\controllers;\n\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\Url;\nuse common\\components\\Controller;\nuse yii\\filters\\AccessControl;\nuse yii\\filters\\VerbFilter;\nuse yii\\authclient\\ClientInterface;\nuse frontend\\modules\\user\\models\\UserAccount;\n\nclass SecurityController extends Controller\n{\n    /**\n     * @inheritdoc\n     */\n    public function behaviors()\n    {\n        return ArrayHelper::merge(parent::behaviors(), [\n            'access' => [\n                'class' => AccessControl::className(),\n                'rules' => [\n                    ['allow' => true, 'actions' => ['login', 'auth'], 'roles' => ['?']],\n                    ['allow' => true, 'actions' => ['logout'], 'roles' => ['@']],\n                ]\n            ],\n            'verbs' => [\n                'class' => VerbFilter::className(),\n                'actions' => [\n                    'logout' => ['post']\n                ]\n            ]\n        ]);\n    }\n\n    public function init()\n    {\n        parent::init();\n        \\Yii::$app->set('authClientCollection', [\n            'class' => 'yii\\authclient\\Collection',\n            'clients' => [\n                // 'google' => [\n                //     'class' => 'yii\\authclient\\clients\\GoogleOAuth',\n                //     'clientId' => \\Yii::$app->setting->get('googleClientId'),\n                //     'clientSecret' => \\Yii::$app->setting->get('googleClientSecret'),\n                // ],\n                'github' => [\n                    'class' => 'yii\\authclient\\clients\\GitHub',\n                    'clientId' => \\Yii::$app->setting->get('githubClientId'),\n                    'clientSecret' => \\Yii::$app->setting->get('githubClientSecret'),\n                ],\n            ],\n        ]);\n    }\n\n    /** @inheritdoc */\n    public function actions()\n    {\n        return [\n            'auth' => [\n                'class' => 'yii\\authclient\\AuthAction',\n                'successCallback' => [$this, 'authenticate'],\n            ]\n        ];\n    }\n\n    /**\n     * Logs the user in if this social account has been already used. Otherwise shows registration form.\n     * @param  ClientInterface $client\n     * @return \\yii\\web\\Response\n     */\n    public function authenticate(ClientInterface $client)\n    {\n        $attributes = $client->getUserAttributes();\n        $provider = $client->getId();\n        $clientId = $attributes['id'];\n\n        $account = UserAccount::find()->where([\n            'provider' => $provider,\n            'client_id' => $clientId\n        ])->one();\n\n        if ($account === null) {\n            $account = \\Yii::createObject([\n                'class' => UserAccount::className(),\n                'provider' => $provider,\n                'client_id' => $clientId,\n                'data' => json_encode($attributes),\n                'created_at' => time()\n            ]);\n            $account->save(false);\n        }\n\n        if (null === ($user = $account->user)) {\n            $this->action->successUrl = Url::to(['/site/connect', 'account_id' => $account->id]);\n        } else {\n            \\Yii::$app->user->login($user, 1209600); // two weeks\n        }\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/controllers/SettingController.php",
    "content": "<?php\n\nnamespace frontend\\modules\\user\\controllers;\n\nuse frontend\\modules\\user\\models\\AvatarForm;\nuse frontend\\modules\\user\\models\\Donate;\nuse Yii;\nuse frontend\\modules\\user\\models\\AccountForm;\nuse common\\models\\UserInfo;\nuse yii\\authclient\\ClientInterface;\nuse yii\\filters\\AccessControl;\nuse frontend\\modules\\user\\models\\UserAccount;\nuse common\\components\\Controller;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\Url;\nuse yii\\web\\ForbiddenHttpException;\nuse yii\\web\\NotFoundHttpException;\nuse yii\\filters\\VerbFilter;\nuse yii\\web\\Response;\nuse yii\\widgets\\ActiveForm;\n\n/**\n * SettingController implements the CRUD actions for User model.\n */\nclass SettingController extends Controller\n{\n    /** @inheritdoc */\n    public $defaultAction = 'profile';\n\n    /** @inheritdoc */\n    public function behaviors()\n    {\n        return ArrayHelper::merge(parent::behaviors(), [\n            'verbs' => [\n                'class' => VerbFilter::className(),\n                'actions' => [\n                    'disconnect' => ['post']\n                ],\n            ],\n            'access' => [\n                'class' => AccessControl::className(),\n                'rules' => [\n                    [\n                        'allow' => true,\n                        'actions' => ['profile', 'account', 'avatar', 'confirm', 'networks', 'connect', 'disconnect', 'donate'],\n                        'roles' => ['@']\n                    ],\n                ]\n            ],\n        ]);\n    }\n\n    public function init()\n    {\n        parent::init();\n        Yii::$app->set('authClientCollection', [\n            'class' => 'yii\\authclient\\Collection',\n            'clients' => [\n                'google' => [\n                    'class' => 'yii\\authclient\\clients\\Google',\n                    'clientId' => Yii::$app->setting->get('googleClientId'),\n                    'clientSecret' => Yii::$app->setting->get('googleClientSecret'),\n                ],\n                'github' => [\n                    'class' => 'yii\\authclient\\clients\\GitHub',\n                    'clientId' => Yii::$app->setting->get('githubClientId'),\n                    'clientSecret' => Yii::$app->setting->get('githubClientSecret'),\n                ],\n            ],\n        ]);\n    }\n\n    /** @inheritdoc */\n    public function actions()\n    {\n        return [\n            'connect' => [\n                'class' => 'yii\\authclient\\AuthAction',\n                'successCallback' => [$this, 'connect'],\n            ]\n        ];\n    }\n\n    /**\n     * 修改个人资料\n     * @return mixed\n     */\n    public function actionProfile()\n    {\n        /** @var UserInfo $model */\n        $model = UserInfo::findOne(['user_id' => Yii::$app->user->id]);\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n\n            $this->flash('更新成功', 'success');\n            return $this->refresh();\n        }\n\n        return $this->render('profile', [\n            'model' => $model,\n        ]);\n    }\n\n    /**\n     * Displays a single User model.\n     * @return string|Response\n     * @throws \\yii\\base\\InvalidConfigException\n     */\n    public function actionAccount()\n    {\n        /** @var AccountForm $model */\n        $model = Yii::createObject(AccountForm::className());\n\n        $this->performAjaxValidation($model);\n\n        if ($model->load(Yii::$app->request->post()) && $model->save()) {\n            Yii::$app->session->setFlash('success', '您的用户信息修改成功');\n            return $this->refresh();\n        }\n\n        return $this->render('account', [\n            'model' => $model,\n        ]);\n    }\n\n    /**\n     *  头像设置\n     * @return mixed\n     */\n    public function actionAvatar()\n    {\n        /** @var AvatarForm $model */\n        $model = Yii::createObject(AvatarForm::className());\n\n        if ($model->load(Yii::$app->request->post())) {\n            if ($model->user->avatar) {\n                // 删除头像\n                $model->deleteImage();\n            }\n            $image = $model->uploadImage();\n            $hasError = true;\n\n            if ($image !== false) {\n                $path = $model->getNewUploadedImageFile();\n                if ($image->saveAs($path)) {\n                    $hasError = false;\n                }\n            }\n\n            if ($hasError) {\n                $model->useDefaultImage();\n            }\n\n            if ($model->save() === false) {\n                $hasError = true;\n            }\n\n            if ($hasError) {\n                Yii::$app->session->setFlash('error', '您的头像更新失败');\n            } else {\n                Yii::$app->session->setFlash('success', '您的用户信息修改成功');\n            }\n            return $this->refresh();\n        }\n\n        return $this->render('avatar', [\n            'model' => $model,\n        ]);\n    }\n\n    /**\n     *   打赏设置\n     * @return mixed\n     */\n    public function actionDonate()\n    {\n        /** @var Donate $model */\n        $model = Donate::findOne(['user_id' => Yii::$app->user->id]) ?: new Donate(['scenario' => 'create']);\n        $oldQrCode = $model->qr_code;\n        $model->description ?: $model->description = '如果这篇文章对您有帮助，不妨微信小额赞助我一下，让我有动力继续写出高质量的教程。';\n\n        if ($model->load(Yii::$app->request->post())) {\n\n            if ($image = $model->uploadImage()) {\n                \\yii\\helpers\\FileHelper::createDirectory(\\Yii::$app->basePath . \\Yii::$app->params['qrCodePath']);\n                $model->deleteImage();\n                $image->saveAs(\\Yii::$app->basePath . \\Yii::$app->params['qrCodePath'] . $model->qr_code);\n            }\n\n            if ($image === false && !empty($oldQrCode)) {\n                $model->qr_code = $oldQrCode;\n            }\n\n            $model->user_id = Yii::$app->user->id;\n\n            if ($model->save()) {\n                Yii::$app->session->setFlash('success', '您的打赏信息修改成功');\n            } else {\n                Yii::$app->session->setFlash('error', '您的打赏信息更新失败');\n            }\n\n            return $this->refresh();\n        }\n\n        return $this->render('donate', [\n            'model' => $model,\n        ]);\n    }\n\n\n    /**\n     *  第三方账号绑定\n     * @return mixed\n     */\n    public function actionNetworks()\n    {\n        return $this->render('networks', [\n            'user' => Yii::$app->user->identity\n        ]);\n    }\n\n    /**\n     * 解除绑定第三方账号\n     * @param $id\n     * @return Response\n     * @throws ForbiddenHttpException\n     * @throws NotFoundHttpException\n     */\n    public function actionDisconnect($id)\n    {\n        /** @var UserAccount $account */\n        $account = UserAccount::findOne(['id' => $id]);\n        if ($account === null) {\n            throw new NotFoundHttpException;\n        }\n        if ($account->user_id != \\Yii::$app->user->id) {\n            throw new ForbiddenHttpException;\n        }\n        $account->delete();\n\n        return $this->redirect(['networks']);\n    }\n\n\n    /**\n     * 绑定第三方账号\n     * @param  ClientInterface $client\n     * @return \\yii\\web\\Response\n     */\n    public function connect(ClientInterface $client)\n    {\n        $attributes = $client->getUserAttributes();\n        $provider = $client->getId();\n        $clientId = $attributes['id'];\n\n        $account = UserAccount::find()->where([\n            'provider' => $provider,\n            'client_id' => $clientId\n        ])->one();\n\n        if ($account === null) {\n            $account = Yii::createObject([\n                'class' => UserAccount::className(),\n                'provider' => $provider,\n                'client_id' => $clientId,\n                'data' => json_encode($attributes),\n                'user_id' => Yii::$app->user->id,\n                'created_at' => time(),\n            ]);\n            $account->save(false);\n            Yii::$app->session->setFlash('success', '账号绑定成功');\n        } else {\n            Yii::$app->session->setFlash('error', '绑定失败，此账号已经绑定过了');\n        }\n\n        $this->action->successUrl = Url::to(['/user/setting/networks']);\n    }\n\n    /**\n     * Performs ajax validation.\n     * @param AccountForm $model\n     * @throws \\yii\\base\\ExitException\n     */\n    protected function performAjaxValidation($model)\n    {\n        if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {\n            Yii::$app->response->format = Response::FORMAT_JSON;\n            Yii::$app->response->data = ActiveForm::validate($model);\n            Yii::$app->response->send();\n            Yii::$app->end();\n        }\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/models/AccountForm.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-30 23:01:28\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-31 21:08:34\n */\n\nnamespace frontend\\modules\\user\\models;\n\nuse common\\components\\Mailer;\nuse yii\\base\\Model;\n\nclass AccountForm extends Model\n{\n    /** @var string */\n    public $email;\n\n    /** @var string */\n    public $username;\n\n    /** @var string */\n    public $tagline;\n\n    /** @var string */\n    public $new_password;\n\n    /** @var string */\n    public $current_password;\n\n    /** @var Module */\n    protected $module;\n\n    /** @var Mailer */\n    protected $mailer;\n\n    /** @var User */\n    private $_user;\n\n    /** @return User */\n    public function getUser()\n    {\n        if ($this->_user == null) {\n            $this->_user = \\Yii::$app->user->identity;\n        }\n\n        return $this->_user;\n    }\n\n    /** @inheritdoc */\n    public function __construct(Mailer $mailer, $config = [])\n    {\n        $this->mailer = $mailer;\n        $this->module = \\Yii::$app->getModule('user');\n        $this->setAttributes([\n            'username' => $this->user->username,\n            'email'    => $this->user->email,\n            'tagline'  => $this->user->tagline,\n        ], false);\n        parent::__construct($config);\n    }\n\n    /** @inheritdoc */\n    public function rules()\n    {\n        return [\n            [['username', 'email', 'current_password'], 'required'],\n            [['username', 'email'], 'filter', 'filter' => 'trim'],\n            ['username', 'match', 'pattern' => '/^[a-zA-Z]\\w+$/'],\n            ['username', 'string', 'min' => 3, 'max' => 20],\n            ['email', 'email'],\n            [['email', 'username'], 'unique', 'when' => function ($model, $attribute) {\n                return $this->user->$attribute != $model->$attribute;\n            }, 'targetClass' => '\\common\\models\\User', 'message' => '此{attribute}已经被使用。'],\n            ['new_password', 'string', 'min' => 6],\n            ['tagline', 'string', 'max' => 40],\n            ['current_password', function ($attr) {\n                if (!\\Yii::$app->security->validatePassword($this->$attr, $this->user->password_hash)) {\n                    $this->addError($attr, '当前密码是输入错误');\n                }\n            }]\n        ];\n    }\n\n    /** @inheritdoc */\n    public function attributeLabels()\n    {\n        return [\n            'email'            => 'Email',\n            'username'         => '用户名',\n            'new_password'     => '新密码',\n            'tagline'          => '一句话介绍',\n            'current_password' => '当前密码'\n        ];\n    }\n\n    /** @inheritdoc */\n    public function formName()\n    {\n        return 'settings-form';\n    }\n\n    /**\n     * Saves new account settings.\n     *\n     * @return bool\n     */\n    public function save()\n    {\n        if ($this->validate()) {\n            $this->user->username = $this->username;\n            // 新密码没填写 则为不修改密码\n            ($this->new_password) ? $this->user->password = $this->new_password : '';\n            $this->user->tagline = $this->tagline;\n            $this->user->email = $this->email;\n            return $this->user->save();\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/models/AvatarForm.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-30 23:01:28\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-31 21:08:34\n */\n\nnamespace frontend\\modules\\user\\models;\n\nuse common\\models\\User;\nuse yii\\base\\Model;\nuse yii\\helpers\\FileHelper;\nuse yii\\web\\UploadedFile;\n\nclass AvatarForm extends Model\n{\n    /** @var string */\n    public $avatar;\n\n    /** @var User */\n    private $_user;\n\n    /** @return User */\n    public function getUser()\n    {\n        if ($this->_user == null) {\n            $this->_user = \\Yii::$app->user->identity;\n        }\n\n        return $this->_user;\n    }\n\n    /** @inheritdoc */\n    public function rules()\n    {\n        return [\n            [['avatar'], 'required'],\n            [['avatar'], 'image', 'extensions' => 'jpg, png, gif, jpeg', 'maxSize' => 1024 * 1024 * 2, 'tooBig' => \\Yii::t('app', 'File has to be smaller than 2MB')],\n        ];\n    }\n\n    /** @inheritdoc */\n    public function attributeLabels()\n    {\n        return [\n            'avatar' => '上传头像',\n        ];\n    }\n\n    /**\n     * Saves new account settings.\n     *\n     * @return bool\n     */\n    public function save()\n    {\n        if ($this->validate()) {\n            $this->user->avatar = $this->avatar;\n            return $this->user->save();\n        }\n        return false;\n    }\n\n    /**\n     * fetch stored image file name with complete path\n     * @return string\n     */\n    public function getImageFile()\n    {\n        return isset($this->user->avatar) ? \\Yii::$app->basePath . \\Yii::$app->params['avatarPath'] . $this->user->avatar : null;\n    }\n\n\n    /**\n     * fetch new generated image file name with complete path\n     * @return string\n     */\n    public function getNewUploadedImageFile()\n    {\n        $uploadAvatarPath = \\Yii::$app->basePath . \\Yii::$app->params['avatarPath'];\n        FileHelper::createDirectory($uploadAvatarPath); // 创建文件夹\n        return isset($this->avatar) ? $uploadAvatarPath . $this->avatar : null;\n    }\n\n    /**\n     * use a default icon in case of errors while processing uploaded files\n     */\n    public function useDefaultImage()\n    {\n        $identicon = new \\Identicon\\Identicon();\n        $this->avatar = $identicon->getImageDataUri($this->user->email);\n    }\n\n    /**\n     * Process upload of image\n     *\n     * @return mixed the uploaded image instance\n     */\n    public function uploadImage()\n    {\n        // get the uploaded file instance. for multiple file uploads\n        // the following data will return an array (you may need to use\n        // getInstances method)\n        $image = UploadedFile::getInstance($this, 'avatar');\n\n        // if no image was uploaded abort the upload\n        if (empty($image)) {\n            return false;\n        }\n\n        // generate a unique file name\n        $this->avatar = \\Yii::$app->security->generateRandomString() . \".{$image->extension}\";\n\n        // the uploaded image instance\n        return $image;\n    }\n\n    /**\n     * Process deletion of image\n     *\n     * @return boolean the status of deletion\n     */\n    public function deleteImage()\n    {\n        $file = $this->getImageFile();\n\n        // check if file exists on server\n        if (empty($file) || !file_exists($file)) {\n            return false;\n        }\n        // 删除缓存的旧头像\n        $avatarCachePath = \\Yii::$app->basePath . \\Yii::$app->params['avatarCachePath'];\n        $files = glob(\"{$avatarCachePath}/*_{$this->user->avatar}\");\n        array_walk($files, function ($file) {\n            unlink($file);\n        });\n\n        // check if uploaded file can be deleted on server\n        if (!unlink($file)) {\n            return false;\n        }\n\n\n        // if deletion successful, reset your file attributes\n        $this->avatar = null;\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/models/Donate.php",
    "content": "<?php\n\nnamespace frontend\\modules\\user\\models;\n\nuse common\\components\\db\\ActiveRecord;\nuse Yii;\nuse yii\\web\\UploadedFile;\n\n/**\n * This is the model class for table \"{{%donate}}\".\n *\n * @property integer $id\n * @property integer $user_id\n * @property integer $status\n * @property string $description\n * @property string $qr_code\n * @property integer $created_at\n * @property integer $updated_at\n */\nclass Donate extends ActiveRecord\n{\n    const STATUS_ACTIVE = 1;\n    const STATUS_DELETE = 0;\n\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%donate}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['user_id'], 'required'],\n            ['qr_code', 'required', 'on' => 'create'],\n            [['user_id', 'status', 'created_at', 'updated_at'], 'integer'],\n            [['qr_code'], 'image', 'extensions' => 'jpg, png, gif, jpeg', 'maxSize' => 1024 * 1024 * 2, 'tooBig' => \\Yii::t('app', 'File has to be smaller than 2MB')],\n            [['description', 'qr_code'], 'string', 'max' => 50]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => Yii::t('app', 'ID'),\n            'user_id' => Yii::t('app', 'User ID'),\n            'status' => Yii::t('app', 'Status'),\n            'description' => Yii::t('app', 'Description'),\n            'qr_code' => Yii::t('app', 'Qr Code'),\n            'created_at' => Yii::t('app', 'Created At'),\n            'updated_at' => Yii::t('app', 'Updated At'),\n        ];\n    }\n\n    /**\n     * Process upload of image\n     *\n     * @return mixed the uploaded image instance\n     */\n    public function uploadImage()\n    {\n        // get the uploaded file instance. for multiple file uploads\n        // the following data will return an array (you may need to use\n        // getInstances method)\n        $image = UploadedFile::getInstance($this, 'qr_code');\n\n        // if no image was uploaded abort the upload\n        if (empty($image)) {\n            return false;\n        }\n\n        // generate a unique file name\n        $this->qr_code = \\Yii::$app->security->generateRandomString() . \".{$image->extension}\";\n        // the uploaded image instance\n        return $image;\n    }\n\n    /**\n     * Process deletion of image\n     *\n     * @return boolean the status of deletion\n     */\n    public function deleteImage()\n    {\n        if (!isset($this->oldAttributes['qr_code']) || !$this->oldAttributes['qr_code']) {\n            return false;\n        }\n\n        $file = \\Yii::$app->basePath . \\Yii::$app->params['qrCodePath'] . $this->oldAttributes['qr_code'];\n        // check if file exists on server\n        if (empty($file) || !file_exists($file)) {\n            return false;\n        }\n\n        // check if uploaded file can be deleted on server\n        if (!unlink($file)) {\n            return false;\n        }\n\n        return true;\n    }\n\n    public static function getStatuses()\n    {\n        return [\n            1 => '开启',\n            0 => '停用',\n        ];\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/models/UserAccount.php",
    "content": "<?php\n\nnamespace frontend\\modules\\user\\models;\n\nuse Yii;\nuse common\\models\\User;\n\n/**\n * This is the model class for table \"user_account\".\n *\n * @property integer $id\n * @property string $user_id\n * @property string $provider\n * @property string $client_id\n * @property string $data\n * @property string $created_at\n */\nclass UserAccount extends \\yii\\db\\ActiveRecord\n{\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%user_account}}';\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['user_id', 'created_at'], 'integer'],\n            [['client_id', 'data'], 'required'],\n            [['data'], 'string'],\n            [['provider'], 'string', 'max' => 100],\n            [['client_id'], 'string', 'max' => 255]\n        ];\n    }\n\n    public function getIsConnected()\n    {\n        return $this->user_id != null;\n    }\n\n    /**\n     * @return User\n     */\n    public function getUser()\n    {\n        return $this->hasOne(User::className(), ['id' => 'user_id']);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'user_id' => '用户ID',\n            'provider' => '授权提供商',\n            'client_id' => 'Client ID',\n            'data' => 'Data',\n            'created_at' => '创建时间',\n        ];\n    }\n}\n"
  },
  {
    "path": "frontend/modules/user/models/UserMeta.php",
    "content": "<?php\n\nnamespace frontend\\modules\\user\\models;\n\nuse common\\models\\PostComment;\nuse common\\services\\NotificationService;\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\tweet\\models\\Tweet;\nuse Yii;\nuse yii\\db\\ActiveRecord;\n\n\n/**\n * This is the model class for table \"user_meta\".\n *\n * @property integer $id\n * @property string $user_id\n * @property string $type\n * @property string $value\n * @property string $target_id\n * @property string $target_type\n * @property string $created_at\n */\nclass UserMeta extends ActiveRecord\n{\n    const STATUS_ACTIVE = 0;\n    const STATUS_DELETED = -1;\n\n    /**\n     * @inheritdoc\n     */\n    public static function tableName()\n    {\n        return '{{%user_meta}}';\n    }\n\n    public function behaviors()\n    {\n        return [\n            'timestamp' => [\n                'class' => 'yii\\behaviors\\TimestampBehavior',\n                'attributes' => [\n                    ActiveRecord::EVENT_BEFORE_INSERT => 'created_at',\n                ],\n            ],\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function rules()\n    {\n        return [\n            [['user_id'], 'required'],\n            [['user_id', 'target_id', 'created_at'], 'integer'],\n            [['type', 'target_type'], 'string', 'max' => 100],\n            [['value'], 'string', 'max' => 255]\n        ];\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function attributeLabels()\n    {\n        return [\n            'id' => 'ID',\n            'user_id' => '用户ID',\n            'type' => '操作类型',\n            'value' => '操作类型值',\n            'target_id' => '目标id',\n            'target_type' => '目标类型',\n            'created_at' => '创建时间',\n        ];\n    }\n\n    public static function deleteOne($conditions)\n    {\n        $model = self::findOne($conditions);\n        if ($model) {\n            return $model->delete();\n        }\n        return false;\n    }\n\n    /**\n     * 判断指定分类下操作是否存在\n     * @param integer $type 话题还是回复\n     * @param string $do 动作\n     * @param integer $targetId 话题ID或者回复ID\n     * @return int|string\n     */\n    public function isUserAction($type = 0, $do = '', $targetId)\n    {\n        return $this->find()->where([\n            'target_id' => $targetId,\n            'user_id' => Yii::$app->user->id,\n            'target_type' => $type,\n            'type' => $do,\n        ])->count();\n    }\n\n    /**\n     * 添加新的动作\n     * @param $type\n     * @param $targetId\n     * @param $do\n     * @return bool\n     */\n    public function saveNewMeta($type, $targetId, $do)\n    {\n        $data = [\n            'target_id' => $targetId,\n            'user_id' => Yii::$app->user->id,\n            'target_type' => $type,\n            'type' => $do,\n        ];\n        $this->deleteAll($data);\n        $model = $this->find()->where($data)->one();\n        $this->setAttributes($data);\n        if (!$model) {\n            if ($this->save()) {\n                return true;\n            } else {\n                return array_values($this->getFirstErrors())[0];\n            }\n        }\n    }\n\n    public function getTopic()\n    {\n        return $this->hasOne(Topic::className(), ['id' => 'target_id']);\n    }\n\n    public function getTweet()\n    {\n        return $this->hasOne(Tweet::className(), ['id' => 'target_id']);\n    }\n\n    public function getComment()\n    {\n        return $this->hasOne(PostComment::className(), ['id' => 'target_id']);\n    }\n\n    public function beforeSave($insert)\n    {\n        if ($insert) {\n            $userActionNotify = (new NotificationService)->findUserActionNotify($this);\n            if ($userActionNotify) {\n                $userActionNotify->delete();\n            }\n            // 点赞、感谢和收藏会收到通知\n            if (in_array($this->type, ['like', 'favorite', 'thanks'])) {\n                switch ($this->target_type) {\n                    case 'topic':\n                        (new NotificationService)->newActionNotify(\n                            $this->target_type . '_' . $this->type,\n                            Yii::$app->user->id,\n                            $this->topic->user_id,\n                            $this->topic\n                        );\n                        break;\n                    case 'tweet':\n                        (new NotificationService)->newActionNotify(\n                            $this->target_type . '_' . $this->type,\n                            Yii::$app->user->id,\n                            $this->tweet->user_id,\n                            $this->tweet\n                        );\n                        break;\n                    case 'comment':\n                        (new NotificationService)->newActionNotify(\n                            $this->target_type . '_' . $this->type,\n                            Yii::$app->user->id,\n                            $this->comment->user_id,\n                            $this->comment->topic,\n                            $this->comment\n                        );\n                        break;\n                    default:\n                        break;\n                }\n            }\n        }\n\n        return parent::beforeSave($insert);\n    }\n\n    public function beforeDelete()\n    {\n        if (parent::beforeDelete()) {\n            $userActionNotify = (new NotificationService)->findUserActionNotify($this);\n            if ($userActionNotify) {\n                $userActionNotify->status = 0;\n                $userActionNotify->save();\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "frontend/modules/user/views/default/_view.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date  :   2015-01-29 23:26:54\n * @Last  Modified by:   forecho\n * @Last  Modified time: 2015-02-04 21:53:45\n */\n\nuse yii\\helpers\\Html;\nuse yii\\helpers\\HtmlPurifier;\nuse yii\\helpers\\Markdown;\n\n?>\n<?php switch ($this->context->action->id) {\n    case 'show':\n        // 回复\n        if ($model->post) {\n            echo Html::a(\n                Html::encode($model->post->title),\n                [\"/{$model->post->type}/default/view\", 'id' => $model->post->id],\n                ['class' => 'list-group-item-heading']\n            );\n            echo Html::tag('span', Yii::$app->formatter->asRelativeTime($model->created_at),\n                ['class' => 'ml5 fade-info']);\n            echo Html::tag('div', HtmlPurifier::process(Markdown::process($model->comment, 'gfm')),\n                ['class' => 'markdown-reply']);\n        }\n        break;\n    case 'favorite':\n    case 'like':\n        // 收藏\n        echo Html::tag('i', '', ['class' => 'fa fa-bookmark red mr5']);\n\n        echo Html::a(\n            Html::encode($model->topic->title),\n            [\"/{$model->topic->type}/default/view\", 'id' => $model->topic->id],\n            ['class' => 'list-group-item-heading']\n        );\n        echo Html::tag('span', Yii::$app->formatter->asRelativeTime($model->topic->created_at),\n            ['class' => 'ml5 fade-info']);\n        echo Html::beginTag('p', ['class' => 'list-group-item-text title-info']);\n\n        echo Html::a($model->topic->category->name,\n            [\"/{$model->topic->type}/default/index\", 'node' => $model->topic->category->alias]);\n        echo ' • ';\n        echo Html::beginTag('span');\n        echo \"{$model->topic->like_count} 个赞 • {$model->topic->comment_count} 条回复\";\n        echo Html::endTag('span');\n        echo Html::endTag('p');\n        break;\n\n    case 'point':\n        // 积分\n        echo Html::tag('i', '', ['class' => 'fa fa-money red mr5']);\n        echo Html::encode($model->description);\n        echo Html::tag('span', Yii::$app->formatter->asRelativeTime($model->created_at), ['class' => 'ml5 fade-info']);\n        break;\n    default:\n        // post 文章\n        echo Html::a(\n            Html::encode($model->title),\n            [\"/{$model->type}/default/view\", 'id' => $model->id],\n            ['class' => 'list-group-item-heading']\n        );\n        echo Html::tag('span', Yii::$app->formatter->asRelativeTime($model->created_at), ['class' => 'ml5 fade-info']);\n        echo Html::beginTag('p', ['class' => 'list-group-item-text title-info']);\n        echo Html::a($model->category->name, [\"/{$model->type}/default/index\", 'node' => $model->category->alias]);\n        echo ' • ';\n        echo Html::beginTag('span');\n        echo \"{$model->like_count} 个赞 • {$model->comment_count} 条回复\";\n        echo Html::endTag('span');\n        echo Html::endTag('p');\n        break;\n} ?>"
  },
  {
    "path": "frontend/modules/user/views/default/show.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\Menu;\nuse yii\\widgets\\ListView;\nuse common\\models\\User;\nuse yii\\helpers\\Url;\n\n$this->title = Html::encode($user->username);\n// $this->params['breadcrumbs'][] = $this->title;\n$username = Yii::$app->getRequest()->getQueryParam('username');\n/** @var User $user*/\n?>\n<section class=\"container user-default-index\">\n\n    <div class=\"col-sm-3\">\n        <!--left col-->\n        <div class=\"panel panel-default thumbnail center\">\n            <div class=\"panel-body\">\n                <div class=\"media\">\n                    <div class=\"media-left media-middle\">\n                        <?= Html::img($user->getUserAvatar(100), ['class' => 'media-object']);?>\n                    </div>\n                    <div class=\"media-body\">\n                        <h2 class=\"mt5\"><?= Html::tag('strong', Html::encode($user->username)) ?></h2>\n                        <p>第 <?= $user->id ?> 位会员</p>\n                        <div class=\"pull-left\">\n                            <span class=\"label label-<?= User::getRole($user->role)['color']?> role\"><?= User::getRole($user->role)['name']?></span>\n                        </div>\n                    </div>\n                </div>\n\n                <div class=\"follow-info row\">\n                    <div class=\"col-sm-4 followers\" data-login=\"rei\">\n                        <a class=\"counter\" href=\"<?= Url::to(['/user/default/point', 'username'=> $username])?>\">\n                            <?= $user->merit ? $user->merit->merit : 0 ?>\n                        </a>\n                        <a class=\"text\" href=\"<?= Url::to(['/user/default/point', 'username'=> $username])?>\">积分</a>\n                    </div>\n                    <div class=\"col-sm-4 following\">\n                        <a class=\"counter\" href=\"#\"><?= $user->userInfo->like_count ?></a>\n                        <a class=\"text\" href=\"#\">赞</a>\n                    </div>\n                    <div class=\"col-sm-4 stars\">\n                        <a class=\"counter\" href=\"#\"><?= $user->userInfo->thanks_count ?></a>\n                        <a class=\"text\" href=\"#\">感谢</a>\n                    </div>\n                </div>\n                <!-- <button type=\"button\" class=\"btn btn-success\">Book me!</button> -->\n                <!-- <button type=\"button\" class=\"btn btn-info\">Send me a message</button> -->\n                <!-- <br> -->\n            </div>\n\n\n        </div>\n\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\"><i class=\"fa fa-user\"></i>个人信息</div>\n            <ul class=\"list-group\">\n                <li class=\"list-group-item text-right\">\n                    <span class=\"pull-left\"><strong class=\"\">加入于</strong></span>\n                    <?= Yii::$app->formatter->asDateTime($user->userInfo->created_at) ?>\n                </li>\n                <?php if ($user->userInfo->location): ?>\n                    <li class=\"list-group-item text-right\">\n                        <span class=\"pull-left\"><strong class=\"\">城市</strong></span>\n                        <?= Html::encode($user->userInfo->location) ?>\n                    </li>\n                <?php endif ?>\n                <?php if ($user->userInfo->company): ?>\n                    <li class=\"list-group-item text-right\">\n                        <span class=\"pull-left\"><strong class=\"\">公司</strong></span>\n                        <?= Html::encode($user->userInfo->company) ?>\n                    </li>\n                <?php endif ?>\n                <?php if ($user->userInfo->github): ?>\n                    <li class=\"list-group-item text-right\">\n                        <span class=\"pull-left\"><strong class=\"\">GitHub</strong></span>\n                        <?= Html::a(Html::encode($user->userInfo->github), Html::encode($user->userInfo->github)) ?>\n                    </li>\n                <?php endif ?>\n                <li class=\"list-group-item text-right\">\n                    <span class=\"pull-left\"><strong class=\"\">最后登录时间</strong></span>\n                    <?= Yii::$app->formatter->asRelativeTime($user->userInfo->last_login_time) ?>\n                </li>\n                <?php if ($user->tagline): ?>\n                    <li class=\"list-group-item text-right\">\n                        <span class=\"pull-left\"><strong class=\"\">签名</strong></span>\n                        <?= Html::encode($user->tagline) ?>\n                    </li>\n                <?php endif ?>\n            </ul>\n        </div>\n\n        <?php if ($user->userInfo->info): ?>\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading\"><i class=\"fa fa-user\"></i>个人简介</div>\n                <div class=\"panel-body\">\n                    <?= Html::encode($user->userInfo->info) ?>\n                </div>\n            </div>\n        <?php endif ?>\n\n        <?php if ($user->userInfo->website): ?>\n            <div class=\"panel panel-default\">\n                <div class=\"panel-heading\"><i class=\"fa fa-link\"></i>个人网站</div>\n                <div class=\"panel-body\">\n                    <?php if (\\yii\\helpers\\Url::isRelative($user->userInfo->website)) {\n                        $user->userInfo->website ='http://' . $user->userInfo->website;\n                    }\n                    echo Html::a(Html::encode($user->userInfo->website), Html::encode($user->userInfo->website)) ?>\n                </div>\n            </div>\n        <?php endif ?>\n\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\"><i class=\"fa fa-dashboard\"></i>个人成就</div>\n            <ul class=\"list-group\">\n                <li class=\"list-group-item text-right\">\n                    <span class=\"pull-left\"><strong class=\"\">发表文章次数</strong></span>\n                    <?= $user->userInfo->post_count ?>\n                </li>\n                <li class=\"list-group-item text-right\">\n                    <span class=\"pull-left\"><strong class=\"\">发布回复次数</strong></span>\n                    <?= $user->userInfo->comment_count ?>\n                </li>\n                <li class=\"list-group-item text-right\">\n                    <span class=\"pull-left\"><strong class=\"\">个人主页浏览次数</strong></span>\n                    <?= $user->userInfo->view_count ?>\n                </li>\n            </ul>\n        </div>\n        <!-- <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">社交网络</div>\n            <div class=\"panel-body\">\n                <i class=\"fa fa-facebook fa-2x\"></i>\n                <i class=\"fa fa-github fa-2x\"></i>\n                <i class=\"fa fa-twitter fa-2x\"></i>\n                <i class=\"fa fa-pinterest fa-2x\"></i>\n                <i class=\"fa fa-google-plus fa-2x\"></i>\n            </div>\n        </div> -->\n    </div>\n    <!--/col-3-->\n    <div class=\"col-sm-9 list-nav mb20\" contenteditable=\"false\" style=\"\">\n        <nav class=\"navbar navbar-default\">\n        <?= Menu::widget([\n            'options' => [\n                'class' => 'nav navbar-nav',\n            ],\n            'items' => [\n                ['label' => '最新回复',  'url' => ['/user/default/show', 'username'=> $username]],\n                ['label' => '最新主题',  'url' => ['/user/default/post', 'username'=> $username]],\n                ['label' => '最新收藏',  'url' => ['/user/default/favorite', 'username'=> $username]],\n                ['label' => '最新赞过主题',  'url' => ['/user/default/like', 'username'=> $username]],\n                ['label' => '积分动态',  'url' => ['/user/default/point', 'username'=> $username]],\n            ]\n        ]) ?>\n        </nav>\n\n        <?= ListView::widget([\n            'dataProvider' => $dataProvider,\n            'itemOptions' => ['class' => 'list-group-item'],\n            'summary' => false,\n            'itemView' => '_view',\n            'options' => ['class' => 'list-group'],\n        ]) ?>\n    </div>\n</section>"
  },
  {
    "path": "frontend/modules/user/views/setting/_alert.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-29 23:01:08\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-31 19:32:42\n */\n\nif ($module->enableFlashMessages): ?>\n    <div class=\"row\">\n        <div class=\"col-xs-12\">\n            <?php foreach (Yii::$app->session->getAllFlashes() as $type => $message): ?>\n                <?php if (in_array($type, ['success', 'danger', 'warning', 'info'])): ?>\n                    <div class=\"alert alert-<?= $type ?>\">\n                        <?= $message ?>\n                    </div>\n                <?php endif ?>\n            <?php endforeach ?>\n        </div>\n    </div>\n<?php endif ?>"
  },
  {
    "path": "frontend/modules/user/views/setting/_menu.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-29 23:01:08\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-02-01 17:08:08\n */\n\nuse yii\\widgets\\Menu;\n\n$user = Yii::$app->user->identity;\n$networksVisible = count(Yii::$app->authClientCollection->clients) > 0;\n\n?>\n\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        <h3 class=\"panel-title\">\n            <?= \\yii\\helpers\\Html::img($user->getUserAvatar(24), ['class' => 'img-rounded', 'alt' => $user->username]);?>\n            <?= $user->username ?>\n        </h3>\n    </div>\n    <div class=\"panel-body\">\n        <?= Menu::widget([\n            'options' => [\n                'class' => 'nav nav-pills nav-stacked'\n            ],\n            'items' => [\n                ['label' => '个人资料',  'url' => ['/user/setting/profile']],\n                ['label' => '账号设置',  'url' => ['/user/setting/account']],\n                ['label' => '更换头像',  'url' => ['/user/setting/avatar']],\n                ['label' => '打赏设置',  'url' => ['/user/setting/donate']],\n                ['label' => '账号绑定', 'url' => ['/user/setting/networks'], 'visible' => $networksVisible],\n            ]\n        ]) ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/modules/user/views/setting/account.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-29 23:26:54\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-31 19:45:14\n */\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n$this->title = '账号设置';\n// $this->params['breadcrumbs'][] = $this->title;\n?>\n\n<?php //echo $this->render('_alert', ['module' => Yii::$app->getModule('user')]) ?>\n<section class=\"container\">\n    <div class=\"col-md-3\">\n        <?= $this->render('_menu') ?>\n    </div>\n    <div class=\"col-md-9\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <?= Html::encode($this->title) ?>\n            </div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin([\n                    'id'          => 'account-form',\n                    'options'     => ['class' => 'form-horizontal'],\n                    'fieldConfig' => [\n                        'template'     => \"{label}\\n<div class=\\\"col-lg-9\\\">{input}</div>\\n<div class=\\\"col-sm-offset-3 col-lg-9\\\">{error}\\n{hint}</div>\",\n                        'labelOptions' => ['class' => 'col-lg-3 control-label'],\n                    ],\n                    'enableAjaxValidation'   => true,\n                    'enableClientValidation' => false,\n                ]); ?>\n\n                <?= $form->field($model, 'email') ?>\n\n                <?= $form->field($model, 'username') ?>\n\n                <?= $form->field($model, 'tagline') ?>\n\n                <?= $form->field($model, 'new_password')->passwordInput()->hint('不填写则不修改密码') ?>\n\n                <hr/>\n\n                <?= $form->field($model, 'current_password')->passwordInput() ?>\n\n                <div class=\"form-group\">\n                    <div class=\"col-lg-offset-3 col-lg-9\">\n                        <?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?><br>\n                    </div>\n                </div>\n\n                <?php ActiveForm::end(); ?>\n            </div>\n        </div>\n    </div>\n</section>\n"
  },
  {
    "path": "frontend/modules/user/views/setting/avatar.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-29 23:23:12\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-30 22:56:49\n */\n\nuse yii\\widgets\\ActiveForm;\nuse yii\\helpers\\Html;\nuse bupy7\\cropbox\\Cropbox;\n\n$this->title = Yii::t('app', 'Avatar');\n?>\n\n<section class=\"container\" xmlns=\"http://www.w3.org/1999/html\">\n    <div class=\"col-md-3\">\n        <?= $this->render('_menu') ?>\n    </div>\n    <div class=\"col-md-9\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <?= Html::encode($this->title) ?>\n            </div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin([\n                    'id'          => 'account-form',\n                    'options'     => ['enctype' => 'multipart/form-data'],\n                ]); ?>\n                <?= Html::img($model->user->getUserAvatar(200)); ?>\n                <?= Html::img($model->user->getUserAvatar(50)); ?>\n                <?= Html::img($model->user->getUserAvatar(24)); ?>\n                <br>\n                <br>\n                <?= $form->field($model, 'avatar')->fileInput(); ?>\n                <div class=\"form-group\">\n                    <?= Html::submitButton(Yii::t('yii', 'Update'), ['class' => 'btn btn-success']) ?><br>\n                </div>\n\n                <?php ActiveForm::end(); ?>\n            </div>\n        </div>\n    </div>\n</section>\n"
  },
  {
    "path": "frontend/modules/user/views/setting/donate.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-29 23:23:12\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-30 22:56:49\n */\n\nuse yii\\widgets\\ActiveForm;\nuse yii\\helpers\\Html;\n\n$this->title = Yii::t('app', 'Donate');\n/** @var \\frontend\\modules\\user\\models\\Donate $model */\n?>\n\n<section class=\"container\">\n    <div class=\"col-md-3\">\n        <?= $this->render('_menu') ?>\n    </div>\n    <div class=\"col-md-9\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <?= Html::encode($this->title) ?>\n            </div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin([\n                    'options' => ['class' => 'form-horizontal', 'enctype' => 'multipart/form-data'],\n                    'fieldConfig' => [\n                        'template' => \"{label}\\n<div class=\\\"col-lg-9\\\">{input}</div>\\n<div class=\\\"col-sm-offset-3 col-lg-9\\\">{error}\\n{hint}</div>\",\n                        'labelOptions' => ['class' => 'col-lg-3 control-label'],\n                    ],\n                ]); ?>\n\n                <?php if ($model->qr_code): ?>\n                    <div class=\"form-group\">\n                        <div class=\"col-lg-offset-3 col-lg-9\">\n                            <?= Html::img(Yii::$app->params['qrCodeUrl'] . $model->qr_code, ['class' => 'img']) ?>\n                        </div>\n                    </div>\n                <?php endif ?>\n                <?= $form->field($model, 'qr_code')->fileInput(); ?><br>\n\n                <?= $form->field($model, 'status')->dropDownList(\\frontend\\modules\\user\\models\\Donate::getStatuses()) ?>\n\n                <?= $form->field($model, 'description')->textarea(['rows' => 2]) ?>\n\n                <div class=\"form-group\">\n                    <div class=\"col-lg-offset-3 col-lg-9\">\n                        <?= Html::submitButton(Yii::t('app', 'Save'), ['class' => 'btn btn-success']) ?><br>\n                    </div>\n                </div>\n\n                <?php ActiveForm::end(); ?>\n            </div>\n        </div>\n    </div>\n</section>\n"
  },
  {
    "path": "frontend/modules/user/views/setting/networks.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-29 23:23:12\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-30 22:56:49\n */\n\nuse frontend\\widgets\\Connect;\nuse yii\\helpers\\Html;\n\n$this->title = 'Networks';\n// $this->params['breadcrumbs'][] = $this->title;\n?>\n\n<?php // $this->render('_alert', ['module' => Yii::$app->getModule('user')]) ?>\n\n<section class=\"container\">\n    <div class=\"col-md-3\">\n        <?= $this->render('_menu') ?>\n    </div>\n    <div class=\"col-md-9\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <?= Html::encode($this->title) ?>\n            </div>\n            <div class=\"panel-body\">\n                <?php $auth = Connect::begin([\n                    'baseAuthUrl' => ['/user/setting/connect'],\n                    'accounts'    => $user->accounts,\n                    'autoRender'  => false,\n                    'popupMode'   => false\n                ]) ?>\n                <table class=\"table\">\n                    <?php foreach ($auth->getClients() as $client): ?>\n                        <tr>\n                            <td style=\"width: 32px\">\n                                <?= Html::tag('span', '', ['class' => 'auth-icon ' . $client->getName()]) ?>\n                            </td>\n                            <td>\n                                <?= $client->getTitle() ?>\n                            </td>\n                            <td style=\"width: 120px\">\n                                <?= $auth->isConnected($client) ?\n                                    Html::a('Disconnect', $auth->createClientUrl($client), [\n                                        'class' => 'btn btn-danger btn-block',\n                                        'data-method' => 'post',\n                                    ]) :\n                                    Html::a('Connect', $auth->createClientUrl($client), [\n                                        'class' => 'btn btn-success btn-block'\n                                    ])\n                                ?>\n                            </td>\n                        </tr>\n                    <?php endforeach; ?>\n                </table>\n                <?php Connect::end() ?>\n            </div>\n        </div>\n    </div>\n</section>\n"
  },
  {
    "path": "frontend/modules/user/views/setting/profile.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-29 23:01:08\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-02-01 22:54:20\n */\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $model common\\models\\UserSettingForm */\n/* @var $form ActiveForm */\n\n$this->title = '个人资料';\n// $this->params['breadcrumbs'][] = $this->title;\n?>\n<section class=\"container user-index\">\n    <div class=\"col-md-3\">\n        <?= $this->render('_menu') ?>\n    </div>\n    <div class=\"col-md-9\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <?= Html::encode($this->title) ?>\n            </div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin([\n                    'id' => 'profile-form',\n                    'options' => ['class' => 'form-horizontal'],\n                    'fieldConfig' => [\n                        'template' => \"{label}\\n<div class=\\\"col-lg-9\\\">{input}</div>\\n<div class=\\\"col-sm-offset-3 col-lg-9\\\">{error}\\n{hint}</div>\",\n                        'labelOptions' => ['class' => 'col-lg-3 control-label'],\n                    ],\n                    'enableAjaxValidation'   => true,\n                    'enableClientValidation' => false,\n                    'validateOnBlur'         => false,\n                ]); ?>\n\n                <?= $form->field($model, 'location') ?>\n\n                <?= $form->field($model, 'company') ?>\n\n                <?= $form->field($model, 'website') ?>\n\n                <?= $form->field($model, 'github') ?>\n\n                <?= $form->field($model, 'info')->textarea(['rows' => 6]) ?>\n\n                <div class=\"form-group\">\n                    <div class=\"col-lg-offset-3 col-lg-9\">\n                        <?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?><br>\n                    </div>\n                </div>\n\n                <?php ActiveForm::end(); ?>\n            </div>\n        </div>\n    </div>\n\n</section>\n"
  },
  {
    "path": "frontend/runtime/.gitignore",
    "content": "*\n!.gitignore"
  },
  {
    "path": "frontend/views/layouts/main.php",
    "content": "<?php\n\nuse frontend\\assets\\AppAsset;\nuse frontend\\assets\\BowerAsset;\nuse frontend\\widgets\\Alert;\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Url;\nuse yii\\widgets\\Breadcrumbs;\n\n//use frontend\\assets\\EmojifyAsset;\n\n\n/* @var $this \\yii\\web\\View */\n/* @var $content string */\n\nAppAsset::register($this);\nBowerAsset::register($this);\n\nrmrevin\\yii\\fontawesome\\AssetBundle::register($this);\n\\frontend\\assets\\EditorAsset::register($this);\n//$emojify = EmojifyAsset::register($this);\n?>\n<?php $this->beginPage() ?>\n<!DOCTYPE html>\n<html lang=\"<?= Yii::$app->language ?>\">\n<head>\n    <meta charset=\"<?= Yii::$app->charset ?>\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <?= Html::csrfMetaTags() ?>\n    <title><?= Html::encode($this->title) ?> - <?= \\Yii::$app->setting->get('siteTitle') ?></title>\n    <meta name=\"keywords\" content=\"<?= \\Yii::$app->setting->get('siteKeyword') ?>\"/>\n    <script type=\"text/javascript\" src=\"https://cdn.wwads.cn/js/makemoney.js\" async></script>\n    <?php $this->head() ?>\n</head>\n<body>\n<?php $this->beginBody() ?>\n<div class=\"wrap\">\n\n    <?= \\frontend\\widgets\\Nav::widget(); ?>\n\n    <div class=\"container\">\n        <div class=\"row\">\n            <?= Breadcrumbs::widget([\n                'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],\n            ]) ?>\n            <?= Alert::widget() ?>\n            <?= $content ?>\n        </div>\n    </div>\n</div>\n\n<footer class=\"footer\">\n    <div class=\"container\">\n        <div class=\"row\">\n            <dl class=\"col-sm-2\">\n                <dt>网站信息</dt>\n                <dd><a href=\"<?= Url::to(['/site/users']) ?>\">活跃会员</a></dd>\n                <dd><a href=\"<?= Url::to(['/site/contributors']) ?>\">贡献者</a></dd>\n            </dl>\n            <dl class=\"col-sm-2\">\n                <dt>相关合作</dt>\n                <dd><a href=\"<?= Url::to(['/site/contact']) ?>\">联系我们</a></dd>\n            </dl>\n            <dl class=\"col-sm-2\">\n                <dt>关注我们</dt>\n                <dd><a href=\"<?= Url::to(['/site/about']) ?>\">关于我们</a></dd>\n                <dd><a href=\"<?= Url::to(['/site/timeline']) ?>\">时间线</a></dd>\n            </dl>\n            <dl class=\"col-sm-3\">\n                <dt> 技术采用</dt>\n                <dd class=\"fs12\">\n                    由 <a href=\"https://github.com/forecho\">forecho</a> 创建 项目地址: <a\n                            href=\"https://github.com/iiyii/getyii\">GetYii</a>\n                    <br/>\n                    <?= Yii::powered() ?> <?= Yii::getVersion() ?>\n                    <br/>\n                    &copy; <?= \\Yii::$app->setting->get('siteName') ?> <?= date('Y') ?>\n                    &nbsp;•&nbsp; <?= floor(Yii::getLogger()->getElapsedTime() * 1000) . ' ms'; ?>\n                </dd>\n            </dl>\n            <div class=\"col-sm-3\">\n                <p>赞助本站，你的LOGO将出现在这里</p>\n            </div>\n        </div>\n    </div>\n</footer>\n\n<div class=\"btn-group-vertical\" id=\"floatButton\">\n    <button type=\"button\" class=\"btn btn-default\" id=\"goTop\" title=\"去顶部\"><span\n                class=\"glyphicon glyphicon-arrow-up\"></span></button>\n    <button type=\"button\" class=\"btn btn-default\" id=\"refresh\" title=\"刷新\"><span\n                class=\"glyphicon glyphicon-repeat\"></span></button>\n    <button type=\"button\" class=\"btn btn-default\" id=\"pageQrcode\" title=\"本页二维码\"><span\n                class=\"glyphicon glyphicon-qrcode\"></span>\n        <img class=\"qrcode\" width=\"130\" height=\"130\"\n             src=\"<?= Url::to(['/site/qr', 'text' => Yii::$app->request->absoluteUrl]) ?>\"/>\n    </button>\n    <button type=\"button\" class=\"btn btn-default\" id=\"goBottom\" title=\"去底部\"><span\n                class=\"glyphicon glyphicon-arrow-down\"></span></button>\n</div>\n\n<div style=\"display:none\">\n    <?= \\Yii::$app->setting->get('siteAnalytics'); ?>\n</div>\n\n<?php\n//$this->registerJs(\n//    'Config = {emojiBaseUrl: \"' . $emojify->baseUrl . '\"};',\n//    \\yii\\web\\View::POS_HEAD\n//);\n?>\n\n<?php $this->endBody() ?>\n</body>\n</html>\n<?php $this->endPage() ?>\n"
  },
  {
    "path": "frontend/views/notification/_item.php",
    "content": "<?php\r\n/**\r\n * author     : forecho <caizh@snsshop.com>\r\n * createTime : 2015/4/23 14:52\r\n * description:\r\n */\r\n\r\nuse yii\\helpers\\Html;\r\nuse yii\\helpers\\HtmlPurifier;\r\n\r\n?>\r\n<?php if ($model->status && $model->post): ?>\r\n    <div class=\"media-left\">\r\n        <?= Html::a(Html::img($model->fromUser->userAvatar, ['class' => 'media-object img-circle']),\r\n            ['/user/default/show', 'username' => $model->fromUser['username']]\r\n        ); ?>\r\n    </div>\r\n    <div class=\"media-body\">\r\n        <div class=\"media-heading\">\r\n            <?= Html::tag('span', Html::a($model->fromUser['username'],\r\n                ['/user/default/show', 'username' => $model->fromUser['username']])); ?>\r\n            <span class=\"info\"><?= $model->getlable($model->type) ?>\r\n                <?= Html::a(Html::encode($model->post->title), ['/topic/default/view', 'id' => $model->post_id],\r\n                    ['title' => $model->post->title]); ?>\r\n        <span class=\"date pull-right\">\r\n            <i class=\"fa fa-clock-o\"></i>\r\n            <?= Html::tag('abbr', Yii::$app->formatter->asRelativeTime($model->created_at),\r\n                ['title' => Yii::$app->formatter->asDatetime($model->created_at)]) ?>\r\n        </span>\r\n        <?php if ($index < $notifyCount) {\r\n            echo Html::tag('span', Yii::t('app', 'New'), ['class' => 'new label label-warning']);\r\n        } ?>\r\n        </div>\r\n        <div class=\"summary markdown\">\r\n            <?= HtmlPurifier::process(\\yii\\helpers\\Markdown::process($model->data, 'gfm')) ?>\r\n        </div>\r\n    </div>\r\n\r\n<?php else: ?>\r\n    <div class=\"media-body\">\r\n        <?= Yii::t('app', 'Data Deleted'); ?>\r\n    </div>\r\n<?php endif ?>\r\n\r\n<div class=\"media-right opts\">\r\n    <?= Html::a(\r\n        Html::tag('i', '', ['class' => 'fa fa-trash']),\r\n        ['/notification/delete', 'id' => $model->id],\r\n        [\r\n            'data' => [\r\n                'method' => 'post',\r\n            ],\r\n        ]\r\n    ) ?>\r\n</div>\r\n"
  },
  {
    "path": "frontend/views/notification/index.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\nuse yii\\widgets\\ListView;\nuse yii\\widgets\\Pjax;\n\n/* @var $this yii\\web\\View */\n/* @var $dataProvider yii\\data\\ActiveDataProvider */\n\n$this->title = Yii::t('app', 'Notifications');\n?>\n<div class=\"container p0 notification-index\">\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading\">\n                <?= Html::a(\n                    Html::tag('i', '', ['class' => 'fa fa-trash']) . ' 清空',\n                    '/notification/clear',\n                    [\n                        'data' => [\n                            'disable-with' => \"清空中...\",\n                            'method' => 'post',\n                        ],\n                        'class' => 'btn btn-danger'\n                    ]\n                ) ?>\n            <?= Html::tag('h4', $this->title, ['class' => 'pull-right']) ?>\n        </div>\n        <?php Pjax::begin(); ?>\n        <?= ListView::widget([\n            'dataProvider' => $dataProvider,\n            'itemOptions' => ['class' => 'media notification'],\n            'summary' => false,\n            'itemView' => '_item',\n            'options' => ['class' => 'panel-body'],\n            'viewParams' => ['notifyCount' => $notifyCount]\n        ]) ?>\n        <?php Pjax::end(); ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/partials/markdwon_help.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/12 上午10:38\n * description: Markdown 提示\n */\n?>\n<div id=\"reply-notice\" style=\"display:none\">\n    <ul>\n        <li><?= \\Yii::t('app', 'publish_typography'); ?></li>\n        <li><?= \\Yii::t('app', 'publish_markdown'); ?></li>\n<!--        <li>--><?//= \\Yii::t('app', 'publish_emoji'); ?><!--</li>-->\n        <li><?= \\Yii::t('app', 'publish_at_user'); ?></li>\n        <li><?= \\Yii::t('app', 'publish_image'); ?></li>\n    </ul>\n</div>"
  },
  {
    "path": "frontend/views/partials/users.php",
    "content": "<?php\n/**\n * author     : forecho <caizh@chexiu.cn>\n * createTime : 2016/4/19 14:44\n * description:\n */\nuse yii\\helpers\\Html;\n/** @var \\yii\\base\\Object $model */\n/** @var \\common\\models\\User $value */\n?>\n\n<?php foreach ($model as $key => $value): ?>\n    <div class=\"col-xs-2\" style=\"min-width: 100px;\">\n        <div class=\"media user-card\">\n            <div class=\"media-left\">\n                <?= Html::a(Html::img($value->userAvatar, ['class' => 'media-object']),\n                    ['/user/default/show', 'username' => $value['username']],\n                    ['title' => $value['username']]\n                ); ?>\n            </div>\n            <div class=\"media-body\">\n                <div class=\"media-heading\">\n                    <?= Html::a(\n                        \\yii\\helpers\\StringHelper::byteSubstr($value['username'], 0, 10),\n                        ['/user/default/show', 'username' => $value['username']],\n                        ['title' => $value['username']]\n                    ); ?>\n                </div>\n                <div class=\"\">\n                    积分：<?= $value->merit ? $value->merit->merit : 0 ?>\n                </div>\n            </div>\n        </div>\n    </div>\n<?php endforeach ?>\n"
  },
  {
    "path": "frontend/views/site/_item.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\n?>\n<li class=\"list-group-item media col-sm-6 mt0\">\n\n    <?= Html::a(Html::tag('span', $model['comment_count'], ['class' => 'badge badge-reply-count']),\n        ['/topic/default/view', 'id' => $model->id, '#' => 'comment' . $model['comment_count']], ['class' => 'pull-right']\n    ); ?>\n\n    <div class=\"avatar pull-left\">\n        <?= Html::a(Html::img($model->user->userAvatar, ['class' => 'media-object']),\n            ['/user/default/show', 'username' => $model->user['username']]\n        ); ?>\n    </div>\n\n    <div class=\"infos\">\n\n        <div class=\"media-heading\">\n            <?= Html::a($model->title,\n                ['/topic/default/view', 'id' => $model->id], ['title' => $model->title]\n            ); ?>\n            <?= ($model->status == 2) ? Html::tag('i', '', ['class' => 'fa fa-trophy excellent']) : null ?>\n        </div>\n        <div class=\"media-body meta title-info\">\n            <?php\n            if ($model->like_count) {\n                echo Html::a(Html::tag('span', ' ' . $model->like_count . ' ', ['class' => 'fa fa-thumbs-o-up']),\n                    ['/topic/default/view', 'id' => $model->id], ['class' => 'remove-padding-left']\n                ), '•';\n            }\n            echo Html::a(\n                $model->category->name,\n                ['/topic/default/index', 'node' => $model->category->alias],\n                ['class' => 'node']\n            ), '•',\n            Html::a(\n                $model->user['username'],\n                ['/user/default/show', 'username' => $model->user['username']]\n            ), '•',\n            Html::tag('span', Yii::$app->formatter->asRelativeTime($model->created_at));\n            ?>\n        </div>\n\n    </div>\n\n</li>"
  },
  {
    "path": "frontend/views/site/about.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n$this->title = '关于';\n$content = '\n#### 这里是 Yii 中文社区\n\n- 爱 PHP，爱 Yii\n- 爱互联网，爱 Web 开发，爱最新最潮的技术\n- 爱学习，爱沟通，也爱传播\n- 我们不管你是谁，只要你喜欢 PHP，喜欢 Yii\n- 这里是 PHP & Yii 的中国社区，作我们最好的交流和沟通的大本营\n\n\n一直以来，Yii 在中国都没有一个靠谱的社区，我们几个打算认真的把这个站做起来，改善中国 Yiier 交流的方式。我们是一个非营利组织，它旨在为中国的 PHP 和 Yii 爱好者提供一个自由，开放的交流平台。\n\nenjoy coding! enjoy yii!\n\n#### 最后\n\n- 感谢 [Ruby-China](https://github.com/ruby-china/ruby-china) 的开源代码。\n- 感谢 [PHPHub](https://github.com/summerblue/phphub) 的开源代码。\n- 感谢 [huajuan](https://github.com/callmez/huajuan) 的开源代码。\n- 最后再感谢一下女朋友的支持 <(▰˘◡˘▰)>。\n';\n?>\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        关于\n    </div>\n    <div class=\"panel-body\">\n        <?= Markdown::process($content, 'gfm') ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/contact.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n$this->title = '联系我们';\n$content = '\n## QQ群\n\n- Yii2 中国交流群：343188481\n- Get√Yii 核心开发者群：321493381（本群只接受参与本站开发的 Yiier）\n\n## 个人联系\n\n- QQ：314494687\n- Mail：caizhenghai[#]gmail.com\n\n';\n?>\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        <?= $this->title ?>\n    </div>\n    <div class=\"panel-body\">\n        <?= Markdown::process($content, 'gfm') ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/contributors.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n$this->title = '贡献者';\n$content = '\n以下是本社区的贡献者名单，排名不分先后。\n\n#### 赞助者\n\n- XXX.\n\n#### 社区维护\n\n- [forecho](/member/forecho)\n- [zghack](/member/zghack)\n\n#### 网站功能开发者\n\n[https://github.com/iiyii/getyii/contributors](https://github.com/iiyii/getyii/contributors)\n\n#### Logo 设计\n\n- [forecho](/member/forecho)\n\n#### 如何贡献？\n\n有钱出钱，有力出力\n\nGithub 项目地址： [https://github.com/iiyii/getyii](https://github.com/iiyii/getyii) Fork 以后提交你的改进，我们会根据情况合并到主线中去，并将你列入贡献者名单。\n\n#### 如何赞助？\n\n![加我微信](/images/wechat-pay.png)\n\n![加我支付宝](/images/ali-pay.png)\n';\n?>\n\n<div class=\"row\">\n    <div class=\"panel panel-default\">\n        <div class=\"panel-heading\"><?= Html::encode($this->title) ?></div>\n        <div class=\"panel-body\">\n            <?= Markdown::process($content, 'gfm') ?>\n        </div>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/error.php",
    "content": "<?php\n\nuse yii\\helpers\\Html;\n\n/* @var $this yii\\web\\View */\n/* @var $name string */\n/* @var $message string */\n/* @var $exception Exception */\n\n$this->title = $name;\n?>\n<section class=\"container site-error\">\n\n    <h1><?= Html::encode($this->title) ?></h1>\n\n    <div class=\"alert alert-danger\">\n        <?= nl2br(Html::encode($message)) ?>\n    </div>\n\n    <p>\n        The above error occurred while the Web server was processing your request.\n    </p>\n    <p>\n        Please contact us if you think this is a server error. Thank you.\n    </p>\n\n</section>\n"
  },
  {
    "path": "frontend/views/site/getstart.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n$this->title = 'Yii 新手入门';\n// $this->params['breadcrumbs'][] = $this->title;\n$content = '\n## Yii 新手入门\n\n### Yii 入门\n\n- [Yii Framework 官网](http://www.yiiframework.com/)\n- [Yii2-中文化组织](https://github.com/yii2-chinesization)\n- [Composer 中文文档](https://github.com/5-say/composer-doc-cn)\n\n#### Yii1\n\n- [Yii1 权威指南中文版](http://www.yiiframework.com/doc/guide/1.1/zh_cn/index)\n- [Yii1 Api 英文版](http://www.yiiframework.com/doc/api/)\n- [Yii1 Demos](http://www.eha.ee/labs/yiiplay/index.php/et)\n- [Yii1 Demos](http://demo.bsourcecode.com/yiiframework/)\n- [Yii1-extension Demo](http://www.eha.ee/labs/yiiplay/index.php/et)\n\n#### Yii2\n\n- [Yii2 权威指南英文版](http://www.yiiframework.com/doc-2.0/guide-index.html)\n- [Yii2 Api 英文版](http://www.yiiframework.com/doc-2.0/index.html)\n- [Yii 2.0权威指南中文版](http://yii2.techbrood.com/guide-index.html)\n- [Yii 2.0权威指南中文版](http://yii2.yiibar.com/guide-zh-CN/guide-README.html)\n- [Yii 2.0权威指南中文版](http://www.yiifans.com/yii2/guide/index.html)\n- [深入理解Yii2.0](http://www.digpage.com)\n- [Krajee Yii Extensions](http://demos.krajee.com/)\n\n\n### Yii 资源\n\n- [Yii 基础教程博客](http://www.bsourcecode.com/)\n- [CSDN Yii 开发教程](http://blog.csdn.net/column/details/mapdigityiiframework.html)\n\n\n### Yii 书籍\n\n- [Yii框架图书](http://www.yiibook.com/)\n\n\n### Yii 优秀开源\n\n#### 基于Yii1\n\n- [yupe](https://github.com/yupe/yupe)\n- [CiiMS](https://github.com/charlesportwoodii/CiiMS)\n- [Yincart](https://github.com/yincart/basic)\n- [dlfblog](https://github.com/windsdeng/dlfblog)\n- [FirCMS](https://github.com/poctsy/fircms)\n- [birdbbs](https://github.com/outman/birdbbs)\n- [dcms](https://github.com/djfly/dcms)\n- [bagecms](http://www.bagecms.com/)\n\n#### 基于Yii2\n\n- [GetYii](https://github.com/iiYii/getyii)\n- [huajuan](https://github.com/callmez/huajuan)\n- [dcms2](https://github.com/djfly/dcms2)\n- [yii2-adminlte](https://github.com/funson86/yii2-adminlte)\n- [yii2-simple](https://github.com/azraf/yii2-simple)\n- [dotplant2](https://github.com/DevGroup-ru/dotplant2)\n\n\n### 贡献者\n\n- [forecho](/member/forecho)\n\n### 最后\n\n欢迎大家跟我联系提供更多资料。\n';\n?>\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        Wiki 列表\n    </div>\n    <div class=\"panel-body\">\n        <?= Markdown::process($content, 'gfm') ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/index.php",
    "content": "<?php\nuse rmrevin\\yii\\fontawesome\\FA;\nuse yii\\helpers\\Html;\nuse yii\\helpers\\HtmlPurifier;\nuse yii\\helpers\\Markdown;\n\n$this->title = \\Yii::$app->setting->get('siteName');\n/** @var array $headline */\n/** @var array $topics */\n/** @var array $statistics */\n/** @var array $users */\n/** @var \\yii\\web\\View $this */\n?>\n    <div class=\"panel panel-default\">\n        <div class=\"panel-body text-center mp0\">\n            <?= ($headline) ? HtmlPurifier::process(Markdown::process(reset($headline), 'gfm')) : \\Yii::t('app', 'site_intro') ?>\n        </div>\n    </div>\n\n    <div class=\"panel panel-default list-panel\">\n        <div class=\"panel-heading\">\n            <h3 class=\"panel-title text-center\">\n                <?= \\Yii::t('app', 'Excellent Topics') ?> &nbsp;\n            </h3>\n        </div>\n\n        <div class=\"clearfix site-index-topic\">\n            <?php if ($topics) {\n                foreach ($topics as $key => $vlaue) {\n                    echo $this->render('_item', ['model' => $vlaue]);\n                }\n            } else {\n                echo \\Yii::t('app', 'Dont have any data Yet');\n            } ?>\n        </div>\n\n        <div class=\"panel-footer text-right\">\n            <span class=\"index_count\">\n                <?= FA::icon('user'); ?><?= \\Yii::t('app', 'Online Count') ?>：<?= $statistics['online_count']; ?>\n                <?= FA::icon('list'); ?><?= \\Yii::t('app', 'Post Count') ?>：<?= $statistics['post_count']; ?>\n                <?= FA::icon('share'); ?><?= \\Yii::t('app', 'Comment Count') ?>：<?= $statistics['comment_count']; ?>\n            </span>\n            <?= Html::a(\\Yii::t('app', 'More Excellent Topics'), ['topic/default/index', 'sort' => 'excellent']) ?>\n        </div>\n    </div>\n\n    <div class=\"panel panel-default list-panel\">\n        <div class=\"panel-heading\">\n            <h3 class=\"panel-title text-center\">社区会员榜</h3>\n        </div>\n\n        <div class=\"panel-body row\">\n            <?= $this->render('/partials/users', ['model' => $users]); ?>\n        </div>\n    </div>\n\n<?= \\frontend\\widgets\\Node::widget() ?>"
  },
  {
    "path": "frontend/views/site/login.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\bootstrap\\ActiveForm;\nuse frontend\\widgets\\Connect;\n\n/* @var $this yii\\web\\View */\n/* @var $form yii\\bootstrap\\ActiveForm */\n/* @var $model \\common\\models\\LoginForm */\n\n$this->title = Yii::t('app', 'Login');\n?>\n\n\n<div class=\"row\">\n    <div class=\"col-md-4 col-sm-offset-3\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">\n                <?= Html::encode($this->title) ?>\n            </div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin(['id' => 'login-form']); ?>\n                <?= $form->field($model, 'username', ['inputOptions' => ['tabindex' => '1']]) ?>\n                <?= $form->field($model, 'password', ['inputOptions' => ['class' => 'form-control', 'tabindex' => '2']])->passwordInput()->label('密码' . ' (' . Html::a('忘记密码？', ['site/request-password-reset'], ['tabindex' => '5']) . ')') ?>\n                <?= $form->field($model, 'rememberMe')->checkbox() ?>\n                <div class=\"form-group\">\n                    <?= Html::submitButton($this->title, ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>\n                </div>\n                <?php ActiveForm::end(); ?>\n            </div>\n            <div class=\"panel-footer\">\n                <?= Html::a(Yii::t('app', 'Sign up'), '/site/signup') ?>\n            </div>\n        </div>\n    </div>\n    <div class=\"col-md-3\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\">用其他平台的帐号登录</div>\n            </br>\n            <?= Connect::widget([\n                'baseAuthUrl' => ['/user/security/auth']\n            ]) ?>\n        </div>\n    </div>\n\n</div>\n"
  },
  {
    "path": "frontend/views/site/markdown.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n$this->title = 'Markdown 教程';\n// $this->params['breadcrumbs'][] = $this->title;\n$content = '\n# Guide\n\n这是一篇讲解如何正确使用 **Markdown** 的排版示例，学会这个很有必要，能让你的文章有更佳清晰的排版。\n\n> 引用文本：Markdown is a text formatting syntax inspired\n\n## 排版\n\n请注意单词拼写，以及中英文排版，https://github.com/sparanoid/chinese-copywriting-guidelines\n\n## 语法指导\n\n### 普通内容\n\n这段内容展示了在内容里面一些小的格式，比如：\n\n- **加粗** - `**加粗**`\n- *倾斜* - `*倾斜*`\n- ~~删除线~~ - `~~删除线~~`\n- `Code 标记` - ``Code 标记``\n- [超级链接](http://github.com) - `[超级链接](http://github.com)`\n- [caizhenghai@gmail.com](mailto:caizhenghai@gmail.com) - `[caizhenghai@gmail.com](mailto:caizhenghai@gmail.com)`\n- ![图片](http://7xjanb.com1.z0.glb.clouddn.com/logo.png) - `![图片](http://7xjanb.com1.z0.glb.clouddn.com/logo.png)`\n\n注：暂不支持上传图片，请使用外链图片。推荐图床：http://drp.io/ 和 https://imgur.com/\n\n### 提及用户\n\n@forecho @caicai ... 通过 @ 可以在发帖和回帖里面提及用户，信息提交以后，被提及的用户将会收到系统通知。以便让他来关注这个帖子或回帖。切记：@某人之后有一个空格。\n\n### 表情符号 Emoji\n\n支持表情符号，你可以用系统默认的 Emoji 符号（无法支持 Chrome 以及 Windows 用户）。\n也可以用图片的表情。\n\n#### 一些表情例子\n\n:smile: :laughing: :dizzy_face: :sob: :cold_sweat: :sweat_smile:  :cry: :triumph: :heart_eyes:  :satisfied: :relaxed: :sunglasses: :weary:\n\n:+1: :-1: :100: :clap: :bell: :gift: :question: :bomb: :heart: :coffee: :cyclone: :bow: :kiss: :pray: :shit: :sweat_drops: :exclamation: :anger:\n\n更多表情请访问：[http://www.emoji-cheat-sheet.com](http://www.emoji-cheat-sheet.com)\n\n### 大标题 - Heading 3\n\n你可以选择使用 H2 至 H6，使用 ##(N) 打头，H1 不能使用，会自动转换成 H2。\n\n> NOTE: 别忘了 # 后面需要有空格！\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6\n\n### 代码块\n\n#### 普通\n\n```\n*emphasize*    **strong**\n_emphasize_    __strong__\n@a = 1\n```\n\n#### 语法高亮支持\n\n如果在 ``` 后面更随语言名称，可以有语法高亮的效果哦，比如:\n\n##### 演示 PHP 代码高亮\n\n```php\npublic function getDataCellValue($model, $key, $index)\n{\n    $value = parent::getDataCellValue($model, $key, $index);\n    return ArrayHelper::getValue($this->enum, $value, $value);\n}\n```\n\n> Tip: 语言名称支持下面这些: `ruby`, `python`, `js`, `html`, `php`, `css`, `coffee`, `bash`, `json`, `xml` ...\n\n### 有序、无序列表\n\n#### 无序列表\n\n- PHP\n  - Yii\n    - ActiveRecord\n- Go\n  - Gofmt\n  - Revel\n- Node.js\n  - Koa\n  - Express\n\n#### 有序列表\n\n1. Node.js\n  1. Express\n  2. Koa\n  3. Sails\n2. PHP\n  1. Yii\n  2. Laravel\n3. Go\n\n\n### 段落\n\n留空白的换行，将会被自动转换成一个段落，会有一定的段落间距，便于阅读。\n\n请注意后面 Markdown 源代码的换行留空情况。\n';\n?>\n<div class=\"panel panel-default user-default-index\">\n    <div class=\"panel-heading\">\n        <?= $this->title; ?>\n    </div>\n    <div class=\"panel-body\">\n        <div class=\"col-md-6\">\n            <pre><code><?= $content ?></code></pre>\n        </div>\n        <div class=\"col-md-6\"><?= Markdown::process($content, 'gfm') ?></div>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/requestPasswordResetToken.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\bootstrap\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $form yii\\bootstrap\\ActiveForm */\n/* @var $model \\frontend\\models\\PasswordResetRequestForm */\n\n$this->title = '找回密码';\n?>\n\n<div class=\"row\">\n    <div class=\"col-md-4 col-sm-offset-3\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\"><?= Html::encode($this->title) ?></div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin(['id' => 'request-password-reset-form']); ?>\n                <?= $form->field($model, 'email') ?>\n                <div class=\"form-group\">\n                    <?= Html::submitButton('Send', ['class' => 'btn btn-primary']) ?>\n                </div>\n                <?php ActiveForm::end(); ?>\n            </div>\n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "frontend/views/site/resetPassword.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\bootstrap\\ActiveForm;\n\n/* @var $this yii\\web\\View */\n/* @var $form yii\\bootstrap\\ActiveForm */\n/* @var $model \\frontend\\models\\ResetPasswordForm */\n\n$this->title = '密码重置';\n?>\n\n<div class=\"row\">\n    <div class=\"col-md-4 col-sm-offset-3\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\"><?= Html::encode($this->title) ?></div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin(['id' => 'reset-password-form']); ?>\n                <?= $form->field($model, 'password')->passwordInput() ?>\n                <div class=\"form-group\">\n                    <?= Html::submitButton(Yii::t('app', 'Save'), ['class' => 'btn btn-primary']) ?>\n                </div>\n                <?php ActiveForm::end(); ?>\n            </div>\n        </div>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/signup.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\bootstrap\\ActiveForm;\nuse frontend\\widgets\\Connect;\n\n/* @var $this yii\\web\\View */\n/* @var $form yii\\bootstrap\\ActiveForm */\n/* @var $model \\frontend\\models\\SignupForm */\n\n$this->title = Yii::t('app', 'Sign up');\n\n?>\n\n<div class=\"row\">\n    <div class=\"col-md-4 col-sm-offset-3\">\n        <div class=\"panel panel-default\">\n            <div class=\"panel-heading\"><?= Html::encode($this->title) ?></div>\n            <div class=\"panel-body\">\n                <?php $form = ActiveForm::begin([\n                    'id' => 'form-signup',\n                    'enableAjaxValidation' => true,\n                    'enableClientValidation' => false\n                ]); ?>\n                <?= $form->field($model, 'username') ?>\n                <?= $form->field($model, 'email') ?>\n                <?= $form->field($model, 'password')->passwordInput() ?>\n                <div class=\"form-group\">\n                    <?= Html::submitButton(Yii::t('app', 'Sign up'), ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>\n                </div>\n                <?php ActiveForm::end(); ?>\n            </div>\n            <div class=\"panel-footer\">\n                <?= Html::a(Yii::t('app', 'Login'), '/site/login') ?>\n            </div>\n        </div>\n    </div>\n</div>\n"
  },
  {
    "path": "frontend/views/site/tags.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n$this->title = '标签云';\n?>\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        <?= $this->title; ?>\n    </div>\n    <div class=\"panel-body tag-cloud\">\n        <?php foreach ($tags as $tag) {\n            $i = (int)($tag->count / 3);\n            echo Html::a($tag->name, ['/topic/default/index', 'tag' => $tag->name], ['class' => 'cloud-' . $i]);\n        } ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/timeline.php",
    "content": "<?php\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Markdown;\n\n/* @var $this yii\\web\\View */\n$this->title = '时间线';\n$content = '\n**2015年5月1日**\n- 网站重新上线，全新改版只做社区！\n- 原来的版本命名为[V1](https://github.com/iiyii/getyii/tree/v1)，可能不会再更新，没有通知系统。\n\n**2015年4月15日**\n- 解决几个BUG\n\n**2015年4月12日**\n- 更换 MarkDown 在线编辑器。\n- 添加统计功能\n\n**2015年3月2日**\n- 在 [yiichina](http://www.yiichina.com/topic/5685) 上发帖推广\n\n**2015年2月14日**\n- 吸引到第一位开发者－[kevin](http://www.getyii.com/member/kevin) 注册账号\n\n**2015年2月06日**\n- 上线测试\n\n';\n?>\n<div class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        <?= $this->title ?>\n    </div>\n    <div class=\"panel-body\">\n        <?= Markdown::process($content, 'gfm') ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/views/site/users.php",
    "content": "<?php\n/* @var $this yii\\web\\View */\n/* @var \\yii\\base\\Object $model */\n$this->title = '活跃用户';\n?>\n<div id=\"about-us\" class=\"panel panel-default\">\n    <div class=\"panel-heading\">\n        <strong>TOP 100 活跃会员</strong>\n        <div class=\"pull-right\">目前已经有 <?= $count ?> 位会员加入了 Get Yii</div>\n    </div>\n\n    <div class=\"panel-body row\">\n        <?= $this->render('/partials/users', ['model' => $model]); ?>\n    </div>\n</div>"
  },
  {
    "path": "frontend/web/.gitignore",
    "content": "/index.php\n/index-test.php\n"
  },
  {
    "path": "frontend/web/.htaccess",
    "content": "# use mod_rewrite for pretty URL support\nRewriteEngine on\n# If a directory or a file exists, use the request directly\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\n# Otherwise forward the request to index.php\nRewriteRule . index.php\n\n# 七牛云存储的回调会传送HTTP_AUTHORIZATION认证秘钥,一定要放在最rewrite的后面.防止影响\n# PHP在CGI模式下的认证信息的获取\n# RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]"
  },
  {
    "path": "frontend/web/assets/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "frontend/web/css/global.css",
    "content": "/*屏蔽流氓宽带商强行插入的广告*/\nbody > iframe {\n    opacity: 0;\n    display: none;\n}\n\nbody {\n    font-family: \"Helvetica Neue\", PingFang SC, Lantinghei SC, Microsoft Yahei, Arial, \"Hiragino Sans GB\", \"Hiragino Sans GB W3\", \"Microsoft YaHei\", \"Wenquanyi Micro Hei\", sans-serif;\n}\n\n.text-center {\n    text-align: center;\n}\n\n.fl {\n    float: left;\n}\n\n.fr {\n    float: right;\n}\n\n.pl0 {\n    padding-left: 0\n}\n\n.pr0 {\n    padding-right: 0\n}\n\n.p0 {\n    padding: 0\n}\n\n.mp0 p, .m0 {\n    margin: 0;\n}\n\n.mt10 {\n    margin-top: 10px;\n}\n\n.mt0 {\n    margin-top: 0;\n}\n\n.mt5 {\n    margin-top: 5px;\n}\n\n.mb0 {\n    margin-bottom: 0;\n}\n\n.mt15 {\n    margin-top: 15px;\n}\n\n.mb20 {\n    margin-bottom: 20px;\n}\n\n.ml5 {\n    margin-left: 5px;\n}\n\n.mr5 {\n    margin-right: 5px;\n}\n\n.mr15 {\n    margin-right: 15px;\n}\n\nh1 {\n    font-size: 24px;\n}\n\nabbr[title] {\n    border-bottom: 0;\n}\n\n.divider {\n    border-bottom: 1px solid #ddd;\n}\n\nh1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {\n    font-weight: bold;\n}\n\nh2 {\n    font-size: 22px;\n}\n\nh3 {\n    font-size: 20px;\n}\n\nh4 {\n    font-size: 18px;\n}\n\n.fs12 {\n    font-size: 12px;\n}\n\n.br0 {\n    border-radius: 0;\n}\n\na {\n    color: #555;\n}\n\na:hover, a:focus {\n    color: #4d5256;\n}"
  },
  {
    "path": "frontend/web/css/site-ruyi.css",
    "content": "html,\nbody {\n    height: 100%;\n    background-color: #fff;\n    font-family: 'Hiragino Sans GB', 'Microsoft YaHei', 微软雅黑, tahoma, arial, simsun, 宋体;\n}\n\n.wrap {\n    min-height: 100%;\n    height: auto;\n    margin: 0 auto -60px;\n    padding: 0 0 60px;\n}\n\n.footer {\n    background-color: #fff;\n    border-top: 1px solid #ddd;\n    padding-top: 50px;\n    padding-bottom: 30px;\n}\n\n.jumbotron {\n    text-align: center;\n    background-color: transparent;\n}\n\n.jumbotron .btn {\n    font-size: 21px;\n    padding: 14px 24px;\n}\n\n.not-set {\n    color: #c55;\n    font-style: italic;\n}\n\n/* add sorting icons to gridview sort links */\na.asc:after, a.desc:after {\n    position: relative;\n    top: 1px;\n    display: inline-block;\n    font-style: normal;\n    font-weight: normal;\n    line-height: 1;\n    padding-left: 5px;\n}\n\na.asc:after {\n    content: /*\"\\e113\"*/ \"\\e151\";\n}\n\na.desc:after {\n    content: /*\"\\e114\"*/ \"\\e152\";\n}\n\n.sort-numerical a.asc:after {\n    content: \"\\e153\";\n}\n\n.sort-numerical a.desc:after {\n    content: \"\\e154\";\n}\n\n.sort-ordinal a.asc:after {\n    content: \"\\e155\";\n}\n\n.sort-ordinal a.desc:after {\n    content: \"\\e156\";\n}\n\n.grid-view th {\n    white-space: nowrap;\n}\n\n.hint-block {\n    display: block;\n    margin-top: 5px;\n    color: #999;\n}\n\n.error-summary {\n    color: #a94442;\n    background: #fdf7f7;\n    border-left: 3px solid #eed3d7;\n    padding: 10px 20px;\n    margin: 0 0 15px 0;\n}\n\n/* 自定义 */\n.navbar, .nav .open > a, .nav .open > a:hover, .nav .open > a:focus {\n    background: #FCFCFC;\n    border-bottom: 1px solid #E5E5E5;\n}\n\n.navbar a, .navbar-default .navbar-nav > li > a {\n    color: #000;\n}\n\n.navbar .nav li.active a:focus, .navbar .nav li.active a:hover, .nav > li > a:hover, .nav > li > a:focus {\n    background-color: #F1F1F1;\n    color: #000;\n}\n\n.navbar .nav li.active a {\n    background-color: #F0F0F0;\n    color: #000;\n}\n.navbar-toggle .icon-bar {\n    background-color: #5CB85C;\n}\n\n@media (min-width: 1400px) {\n    .container {\n        width: 1400px;\n    }\n}\n\n.list-group {\n    margin-bottom: 0;\n    background-color: #f5f5f5;\n}\n\n.col-md-10 {\n    padding-left: 0;\n}\n\n.site-index-topic .list-group-item:last-child {\n    border-bottom: 0px;\n}\n\n.topic-view .info {\n    color: #c0c0c0;\n    font-size: 12px;\n}\n\n.topic-view .panel-heading {\n    padding: 15px;\n}\n\n.topic-view .panel-heading h1 {\n    font-size: 24px;\n}\n\n.list-group-item {\n    border: none;\n    margin-bottom: 0;\n    border-bottom: 1px solid #ddd;\n}\n\n.pagination {\n    margin-left: 15px;\n}\n\n.article a {\n    color: #008E59;\n}\n\n.topic-view .active .fa, .filter .active, .red {\n    color: #EB5424;\n}\n\n#reply-notice {\n    color: gray;\n    padding-top: 16px;\n    margin-bottom: 16px;\n    border: 1px dashed;\n}\n\n.opts a:link, .opts a:visited {\n    color: #666;\n    text-decoration: none;\n}\n\n.opts a {\n    margin-right: 5px;\n}\n\n#topic-view .info .opts a {\n    margin-left: 5px;\n    color: #999;\n}\n\n.empty {\n    padding: 10px 15px;\n}\n\n#md-preview {\n    padding: 10px;\n    margin-bottom: 15px;\n    border: 1px dashed #ccc;\n}\n\n/*代码高亮*/\n.article pre, .markdown-reply pre {\n    padding: 0;\n}\n\n.deleted {\n    text-decoration: line-through;\n    color: #e1e1e1;\n}\n\n#about-us h5 {\n    font-size: 13px;\n}\n\n.notification-count .new {\n    color: #F86334;\n}\n\n.notification-count span {\n    margin-left: 3px;\n    font-size: 12px;\n}\n\n.title-info {\n    color: #aaa;\n    font-size: 12px;\n    margin-top: 10px;\n}\n\n.title-info .node {\n    padding: 1px 5px;\n    text-decoration: none;\n    background-color: #efefef;\n}\n\n.title-info a {\n    color: #666;\n}\n\n.notification-index .notification {\n    position: relative;\n    margin-bottom: 15px;\n    padding-bottom: 15px;\n    border-bottom: 1px solid #F0F4F6;\n}\n\n.badge-reply-count {\n    margin-top: 15px;\n    background-color: #98ACDF;\n}\n\na:visited .badge-reply-count {\n    background-color: #d7d7d7;\n}\n\n.excellent {\n    color: #EB5424;\n}\n\n.node-box dt {\n    color: #999;\n    font-weight: 400;\n}\n\n.node-box dd, .node-box dt {\n    padding: 15px 0 4px;\n}\n\n.ribbon-excellent {\n    font-size: 13px;\n    background: #FCF8F7;\n    padding: 3px 15px;\n    border-top: 1px solid #eae5e4;\n    color: #aAa5a4;\n    margin: 0 -15px -15px;\n}\n\n.side-bar .list {\n    padding-left: 15px;\n}\n\n.tag-cloud a {\n    padding: 10px;\n}\n\n.tag-cloud .cloud-1 {\n    font-size:120%;\n}\n\n.tag-cloud .cloud-2 {\n    font-size:140%;\n}\n\n.tag-cloud .cloud-3 {\n    font-size:160%;\n}\n\n.tag-cloud .cloud-4 {\n    font-size:180%;\n}\n\n.tag-cloud .cloud-5 {\n    font-size:200%;\n}\n\n.tag-cloud .cloud-6 {\n    font-size:220%;\n}\n\n/* add by ruzuojun */\n#floatButton {position:fixed;top:50%;right:0;z-index:9999999;}\n#floatButton .btn:focus{outline:0}\n@media screen and (max-width: 767px) {\n    #floatButton {display:none;}\n}\n#pageQrcode img.qrcode{position:absolute;right:50px;bottom:-34px;padding:10px;background:#fff;border:1px solid #ccc;border-radius:4px;display:none}\n#pageQrcode:hover img.qrcode{display:block}"
  },
  {
    "path": "frontend/web/css/site.css",
    "content": "html,\nbody {\n    height: 100%;\n    background-color: #f0f0f0;\n    padding-top: 35px;\n}\n\n.wrap {\n    min-height: 100%;\n    height: auto;\n    margin: 0 auto -60px;\n    padding: 0 0 60px;\n}\n\n.footer {\n    background-color: #fff;\n    border-top: 1px solid #ddd;\n    padding-top: 50px;\n    padding-bottom: 30px;\n}\n\n.jumbotron {\n    text-align: center;\n    background-color: transparent;\n}\n\n.jumbotron .btn {\n    font-size: 21px;\n    padding: 14px 24px;\n}\n\n.not-set {\n    color: #c55;\n    font-style: italic;\n}\n\n/* add sorting icons to gridview sort links */\na.asc:after, a.desc:after {\n    position: relative;\n    top: 1px;\n    display: inline-block;\n    font-style: normal;\n    font-weight: normal;\n    line-height: 1;\n    padding-left: 5px;\n}\n\na.asc:after {\n    content: /*\"\\e113\"*/ \"\\e151\";\n}\n\na.desc:after {\n    content: /*\"\\e114\"*/ \"\\e152\";\n}\n\n.sort-numerical a.asc:after {\n    content: \"\\e153\";\n}\n\n.sort-numerical a.desc:after {\n    content: \"\\e154\";\n}\n\n.sort-ordinal a.asc:after {\n    content: \"\\e155\";\n}\n\n.sort-ordinal a.desc:after {\n    content: \"\\e156\";\n}\n\n.grid-view th {\n    white-space: nowrap;\n}\n\n.hint-block {\n    display: block;\n    margin-top: 5px;\n    color: #999;\n}\n\n.error-summary {\n    color: #a94442;\n    background: #fdf7f7;\n    border-left: 3px solid #eed3d7;\n    padding: 10px 20px;\n    margin: 0 0 15px 0;\n}\n\n/* 自定义 */\n.navbar, .nav .open > a, .nav .open > a:hover, .nav .open > a:focus {\n    background: #FFF;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.11);\n}\n\n.navbar a, .navbar-default .navbar-nav > li > a {\n    color: #333;\n}\n\n.navbar .nav li.active a:focus, .navbar .nav li.active a:hover, .nav > li > a:hover, .nav > li > a:focus {\n    background-color: #FFF;\n    color: #000;\n}\n\n.navbar .nav li.active a {\n    background-color: #FFF;\n    border-bottom: 3px solid #5CB85C;\n    color: #5CB85C;\n}\n\n.navbar-toggle .icon-bar {\n    background-color: #5CB85C;\n}\n\n.list-group {\n    margin-bottom: 0;\n    background-color: #f5f5f5;\n}\n\n.site-index-topic .list-group-item:last-child {\n    border-bottom: 0;\n}\n\n.topic .tab {\n    background-color: #fff;\n}\n\n.topic .tab a {\n    padding: 5px 8px 5px 8px;\n    border-radius: 3px;\n}\n\n.topic .tab a:hover {\n    background-color: #f5f5f5;\n    color: #000;\n    text-decoration: none;\n}\n\n.topic .tab a.active {\n    background-color: #5CB85C;\n    color: #fff;\n}\n\n.topic .children a.children-node {\n    padding: 0 10px;\n}\n\n.topic .title {\n    font-size: 16px;\n}\n\n.node-header .title {\n    font-size: 24px;\n    color: #333;\n    margin-bottom: 8px;\n}\n\n.node-header .title .total {\n    color: #999;\n    font-size: 14px;\n    margin-left: 10px;\n}\n\n.topic-view .info {\n    color: #c0c0c0;\n    font-size: 12px;\n}\n\n.topic-view .panel-heading {\n    padding: 15px;\n}\n\n.topic-view .panel-heading h1 {\n    font-size: 24px;\n}\n\n.list-group-item {\n    border: none;\n    margin-bottom: 0;\n    border-bottom: 1px solid #ddd;\n}\n\n.pagination {\n    margin-left: 15px;\n}\n\n.article a {\n    color: #008E59;\n}\n\n.article img, .markdown-reply img, .text-center img, .img {\n    max-width: 100%;\n}\n\n.tweet .active .fa, .topic-view .active .fa, .filter .active, .red {\n    color: #EB5424;\n}\n\n#reply-notice {\n    color: gray;\n    padding-top: 16px;\n    margin-bottom: 16px;\n    border: 1px dashed;\n}\n\n.opts a:link, .opts a:visited {\n    color: #666;\n    text-decoration: none;\n}\n\n.opts a {\n    margin-right: 5px;\n}\n\n#topic-view .info .opts a {\n    margin-left: 5px;\n    color: #999;\n}\n\n.empty {\n    padding: 10px 15px;\n}\n\n#md-preview {\n    padding: 10px;\n    margin-bottom: 15px;\n    border: 1px dashed #ccc;\n}\n\n.article {\n    margin-top: 0;\n    margin-bottom: 0;\n    margin-right: auto;\n    line-height: 2;\n    color: #424b50;\n    word-wrap: break-word;\n    font-size: 14px;\n    -webkit-font-smoothing: antialiased;\n    -webkit-text-size-adjust: 100%;\n    -ms-text-size-adjust: 100%;\n    counter-reset: entry825h2 entry825h3 entry825h4 entry825h5 entry825h6;\n}\n\n.article p {\n    padding: 0;\n    margin-top: 12px;\n    margin-bottom: 12px;\n}\n\n/*代码高亮*/\n.article pre, .user-default-index pre, .markdown pre, .markdown-reply pre, .tweet pre {\n    font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n    padding: 0;\n}\n\n.article blockquote, .markdown-reply blockquote, #md-preview blockquote, blockquote {\n    background-color: #f7f7f7;\n    font-size: inherit;\n}\n\n.deleted {\n    text-decoration: line-through;\n    color: #e1e1e1;\n}\n\n#about-us h5 {\n    font-size: 13px;\n}\n\n.notification-count .new {\n    color: #F86334;\n}\n\n.notification-count span {\n    margin-left: 3px;\n    font-size: 12px;\n}\n\n.title-info {\n    margin-top: 10px;\n}\n\n.fade-info, .title-info {\n    color: #aaa;\n    font-size: 12px;\n}\n\n.title-info .node {\n    padding: 1px 5px;\n    text-decoration: none;\n    background-color: #efefef;\n}\n\n.title-info a {\n    color: #666;\n}\n\n.notification-index .notification {\n    position: relative;\n    margin-bottom: 15px;\n    padding-bottom: 15px;\n    border-bottom: 1px solid #F0F4F6;\n}\n\n.badge-reply-count {\n    margin-top: 15px;\n    background-color: #98ACDF;\n}\n\na:visited .badge-reply-count {\n    background-color: #d7d7d7;\n}\n\n.excellent {\n    color: #EB5424;\n}\n\n.node-box dt {\n    color: #999;\n    font-weight: 400;\n}\n\n.node-box dd, .node-box dt {\n    padding: 15px 0 4px;\n}\n\n.ribbon-excellent {\n    font-size: 13px;\n    background: #FCF8F7;\n    padding: 3px 15px;\n    border-top: 1px solid #eae5e4;\n    color: #aAa5a4;\n    margin: 10px -15px -15px;\n}\n\n.side-bar .list {\n    padding-left: 15px;\n}\n\n.tag-cloud a {\n    padding: 10px;\n}\n\n.tag-cloud .cloud-1 {\n    font-size: 120%;\n}\n\n.tag-cloud .cloud-2 {\n    font-size: 140%;\n}\n\n.tag-cloud .cloud-3 {\n    font-size: 160%;\n}\n\n.tag-cloud .cloud-4 {\n    font-size: 180%;\n}\n\n.tag-cloud .cloud-5 {\n    font-size: 200%;\n}\n\n.tag-cloud .cloud-6 {\n    font-size: 220%;\n}\n\n/* add by ruzuojun */\n#floatButton {\n    position: fixed;\n    top: 50%;\n    right: 0;\n    z-index: 9999999;\n}\n\n#floatButton .btn:focus {\n    outline: 0\n}\n\n@media screen and (max-width: 767px) {\n    #floatButton {\n        display: none;\n    }\n}\n\n#pageQrcode img.qrcode {\n    position: absolute;\n    right: 50px;\n    bottom: -34px;\n    padding: 10px;\n    background: #fff;\n    border: 1px solid #ccc;\n    border-radius: 4px;\n    display: none\n}\n\n#pageQrcode:hover img.qrcode {\n    display: block\n}\n\n.index_count {\n    float: left;\n    font-size: 12px;\n    margin-top: 3px;\n}\n\n#editor {\n    border: 1px solid #ddd;\n    padding: 6px 6px 0 6px;\n}\n\n.select2-container--krajee .select2-results > .select2-results__options {\n    max-height: 500px;\n}\n\nimg.emoji {\n    width: 1.5em;\n    height: 1.5em;\n    margin: 0 .1em;\n    vertical-align: -0.1em;\n    display: inline-block;\n}\n\n.donate p {\n    margin-top: 10px;\n    font-size: 12px;\n    color: #666;\n}\n\n.follow-info {\n    border-top: 1px solid #f0f0f0;\n    text-align: center;\n    margin-top: 15px;\n    padding-top: 15px;\n}\n\n.follow-info a {\n    display: block;\n    text-decoration: none;\n}\n\n.follow-info a.text {\n    color: #999;\n}\n\n.follow-info a.counter {\n    font-size: 32px;\n    color: #5CB85C;\n}\n\n.tweet h1, .tweet h2, .tweet h3, .tweet h4 {\n    font-size: 14px;\n}\n\n.user-card {\n    margin-bottom: 15px;\n}\n\n.p-fixed {\n    position: fixed;\n    display: block;\n    width: 292px;\n    z-index: 99;\n}\n\n.hide {\n    display: none;\n}\n\n.show {\n    display: inline;\n}\n\n#donate-qr-code {\n    display: none;\n}\n\n.numbers {\n    float: left;\n    width: 80px;\n    height: 42px;\n    top: 10px;\n    left: 0;\n    text-align: center;\n}\n\n.numbers .like-num, .numbers .read-num {\n    float: left;\n    width: 50%;\n    display: block;\n}\n\n.numbers div.like-num p {\n    color: #5CB85C;\n}"
  },
  {
    "path": "frontend/web/js/At.js",
    "content": "/**\n * Created by Administrator on 2016/3/10.\n */\nvar emojis = [\"plus1\", \"ok_hand\", \"joy\", \"clap\", \"smile\", \"smirk\", \"sleepy\", \"smiley\", \"heart\", \"kiss\", \"copyright\", \"coffee\"];\nvar emojisList = $.map(emojis, function (value, i) {\n    return {'id': i, 'name': value};\n});\n$(\".field-md-input textarea\").atwho({\n    at: ':',\n    displayTpl: \"<li><img src='https://cdn.learnku.com/assets/images/emoji/${name}.png' height='20' width='20'/> ${name} </li>\",\n    insertTpl: \":${name}:\",\n    data: emojisList\n}).atwho({\n    at: \"@\",\n    data: \"/at-users\",\n    //data: [\"one\", \"two\", \"three\"],\n    limit: 6\n});\n$(\"[data-at-topic]\").atwho({ // 动弹话题\n    at: \"#\",\n    data: ['每日打卡', '干货分享', '心情', '小贴士'],\n    limit: 6,\n    suffix: '# '\n});\n$(\"[data-at-floor]\").atwho({ // 楼层\n    at: \"#\",\n    data: Array.apply(null, Array(99)).map(function (_, i) {\n        return (i + 1) + '楼';\n    }),\n    limit: 6,\n    suffix: ' '\n});"
  },
  {
    "path": "frontend/web/js/editor.js",
    "content": "// function insertString (merged, line) {\n//     var editor = ace.edit(\"markdown\");\n//     editor.$blockScrolling = Infinity;\n//     var source = editor.getValue();\n//     var prefixBreak = source ? \"\\n\" : '';\n//     var srcMerged = prefixBreak + merged;\n//     editor.insert(srcMerged);\n//     editor.gotoLine(editor.getCursorPosition().row + line);\n// }\n//\n// $('.insert-codes a').click(function (e) {\n//     e.preventDefault();\n//     var language = $(this).data('lang');\n//     insertString(\"```\" + language + \"\\n\\n```\\n\", -1);\n// });\n// // var $editor = $('#md-input').dropzone({\n// //     url: \"https://sm.ms/api/upload\",\n// //     paramName: 'smfile',\n// //     clickable: true,\n// //     previewsContainer: '#dropzone-previewer',\n// //     headers: { 'Cache-Control': null, 'X-Requested-With': null },\n// //     success: function(file, response){\n// //         if (response.code == 'success') {\n// //             var img = response.data.url;\n// //             insertString(\"![](\" + img + \")\\n\", 1);\n// //         } else {\n// //             alert(response.msg);\n// //         }\n// //     }\n// // });\n//\n// // $('#topic-upload-image').click(function(e){\n// //     $editor.click();\n// // })\n//\n"
  },
  {
    "path": "frontend/web/js/jquery.pin.js",
    "content": "(function ($) {\n    \"use strict\";\n    $.fn.pin = function (options) {\n        var scrollY = 0, elements = [], disabled = false, $window = $(window);\n\n        options = options || {};\n\n        var recalculateLimits = function () {\n            for (var i=0, len=elements.length; i<len; i++) {\n                var $this = elements[i];\n\n                if (options.minWidth && $window.width() <= options.minWidth) {\n                    if ($this.parent().is(\".pin-wrapper\")) { $this.unwrap(); }\n                    $this.css({width: \"\", left: \"\", top: \"\", position: \"\"});\n                    if (options.activeClass) { $this.removeClass(options.activeClass); }\n                    disabled = true;\n                    continue;\n                } else {\n                    disabled = false;\n                }\n\n                var $container = options.containerSelector ? $this.closest(options.containerSelector) : $(document.body);\n                var offset = $this.offset();\n                var containerOffset = $container.offset();\n                var parentOffset = $this.offsetParent().offset();\n\n                if (!$this.parent().is(\".pin-wrapper\")) {\n                    $this.wrap(\"<div class='pin-wrapper'>\");\n                }\n\n                var pad = $.extend({\n                  top: 0,\n                  bottom: 0\n                }, options.padding || {});\n\n                $this.data(\"pin\", {\n                    pad: pad,\n                    from: (options.containerSelector ? containerOffset.top : offset.top) - pad.top,\n                    to: containerOffset.top + $container.height() - $this.outerHeight() - pad.bottom,\n                    end: containerOffset.top + $container.height(),\n                    parentTop: parentOffset.top\n                });\n\n                $this.css({width: $this.outerWidth()});\n                $this.parent().css(\"height\", $this.outerHeight());\n            }\n        };\n\n        var onScroll = function () {\n            if (disabled) { return; }\n\n            scrollY = $window.scrollTop();\n\n            var elmts = [];\n            for (var i=0, len=elements.length; i<len; i++) {          \n                var $this = $(elements[i]),\n                    data  = $this.data(\"pin\");\n\n                if (!data) { // Removed element\n                  continue;\n                }\n\n                elmts.push($this); \n                  \n                var from = data.from - data.pad.bottom,\n                    to = data.to - data.pad.top;\n              \n                if (from + $this.outerHeight() > data.end) {\n                    $this.css('position', '');\n                    continue;\n                }\n              \n                if (from < scrollY && to > scrollY) {\n                    !($this.css(\"position\") == \"fixed\") && $this.css({\n                        left: $this.offset().left,\n                        top: data.pad.top\n                    }).css(\"position\", \"fixed\");\n                    if (options.activeClass) { $this.addClass(options.activeClass); }\n                } else if (scrollY >= to) {\n                    $this.css({\n                        left: \"\",\n                        top: to - data.parentTop + data.pad.top\n                    }).css(\"position\", \"absolute\");\n                    if (options.activeClass) { $this.addClass(options.activeClass); }\n                } else {\n                    $this.css({position: \"\", top: \"\", left: \"\"});\n                    if (options.activeClass) { $this.removeClass(options.activeClass); }\n                }\n          }\n          elements = elmts;\n        };\n\n        var update = function () { recalculateLimits(); onScroll(); };\n\n        this.each(function () {\n            var $this = $(this), \n                data  = $(this).data('pin') || {};\n\n            if (data && data.update) { return; }\n            elements.push($this);\n            $(\"img\", this).one(\"load\", recalculateLimits);\n            data.update = update;\n            $(this).data('pin', data);\n        });\n\n        $window.scroll(onScroll);\n        $window.resize(function () { recalculateLimits(); });\n        recalculateLimits();\n\n        $window.load(update);\n\n        return this;\n      };\n})(jQuery);\n"
  },
  {
    "path": "frontend/web/js/main.js",
    "content": "jQuery(function ($) {\n  function notificationsCount() {\n    var notification = $(\".notification-count\");\n    var originalTitle = document.title;\n    if (notification.length > 0) {\n      function scheduleGetNotification() {\n        $.get(location.origin + \"/notification/count\", function (data) {\n          var nCount = parseInt(data);\n          if (nCount > 0) {\n            $(\".notification-count a span\").text(nCount);\n            $(\".notification-count a\").addClass(\"new\");\n            document.title = \"(\" + nCount + \") \" + originalTitle;\n          } else {\n            document.title = originalTitle;\n            $(\".notification-count a span\").text(\"\");\n            $(\".notification-count a\").removeClass(\"new\");\n          }\n          setTimeout(scheduleGetNotification, 15000);\n        });\n      }\n\n      setTimeout(scheduleGetNotification, 15000);\n    }\n  }\n\n  notificationsCount();\n\n  // 新窗口打开外链\n  $('a[href^=\"http://\"], a[href^=\"https://\"]').each(function () {\n    var a = new RegExp(\"/\" + window.location.host + \"/\");\n    if (!a.test(this.href)) {\n      $(this).click(function (event) {\n        event.preventDefault();\n        event.stopPropagation();\n        window.open(this.href, \"_blank\");\n      });\n    }\n  });\n\n  // 加载代码高亮\n  hljs.initHighlightingOnLoad();\n\n  emojify.setConfig({\n    img_dir: \"https://cdn.learnku.com/assets/images/emoji/\",\n  });\n  emojify.run();\n\n  function localStorage() {\n    $(\"#md-input\").focus(function (event) {\n      // Topic Title ON Topic Creation View\n      localforage.getItem(\"topic_title\", function (err, value) {\n        if ($(\".topic-create #topic-title\").val() == \"\" && !err) {\n          $(\".topic-create #topic-title\").val(value);\n        }\n      });\n      $(\".topic-create #topic-title\").keyup(function () {\n        localforage.setItem(\"topic_title\", $(this).val());\n      });\n\n      // Topic Content ON Topic Creation View\n      localforage.getItem(\"topic_create_content\", function (err, value) {\n        if ($(\".topic-create #md-input\").val() == \"\" && !err) {\n          $(\".topic-create #md-input\").val(value);\n          runPreview();\n        }\n      });\n      $(\".topic-create #md-input\").keyup(function () {\n        localforage.setItem(\"topic_create_content\", $(this).val());\n        runPreview();\n      });\n\n      // Reply Content ON Topic Detail View\n      localforage.getItem(\"comment_content\", function (err, value) {\n        if ($(\".topic-view #md-input\").val() == \"\" && !err) {\n          $(\".topic-view #md-input\").val(value);\n          runPreview();\n        }\n      });\n      $(\".topic-view #md-input\").keyup(function () {\n        localforage.setItem(\"comment_content\", $(this).val());\n        runPreview();\n      });\n    });\n\n    // Clear Local Storage on submit\n    $(\".topic-create button[type=submit]\").click(function (event) {\n      localforage.removeItem(\"topic_create_content\");\n      localforage.removeItem(\"topic_title\");\n    });\n    $(\".topic-view button[type=submit]\").click(function (event) {\n      localforage.removeItem(\"comment_content\");\n    });\n  }\n\n  localStorage();\n\n  //add by ruzuojun\n  $(document)\n    .on(\"click\", \"#goTop\", function () {\n      $(\"html,body\").animate({ scrollTop: \"0px\" }, 800);\n    })\n    .on(\"click\", \"#goBottom\", function () {\n      $(\"html,body\").animate({ scrollTop: $(\".footer\").offset().top }, 800);\n    })\n    .on(\"click\", \"#refresh\", function () {\n      location.reload();\n    });\n\n  //打赏显示和隐藏切换\n  $(\"#donate-btn\").click(function () {\n    $(\"#donate-qr-code\").toggle();\n  });\n\n  // 防止重复提交\n  $(\"form\").on(\"submit\", function () {\n    var $form = $(this),\n      data = $form.data(\"yiiActiveForm\");\n    if (data) {\n      // 如果是第一次 submit 并且 客户端验证有效，那么进行正常 submit 流程\n      if (!$form.data(\"getyii.submitting\") && data.validated) {\n        $form.data(\"getyii.submitting\", true);\n        return true;\n      } else {\n        //  否则阻止提交\n        return false;\n      }\n    }\n  });\n\n  // function called if wwads is blocked\n  function ABDetected() {\n    var adBlockDetected_div = document.createElement(\"div\");\n    adBlockDetected_div.style.cssText =\n      \"position: absolute; top: 0; left: 0; width: 100%; background: #fc6600; color: #fff; z-index: 9999999999; font-size: 14px; text-align: center; line-height: 1.5; font-weight: bold; padding-top: 6px; padding-bottom: 6px;\";\n    adBlockDetected_div.innerHTML =\n      \"我们的广告服务商 <a style='color:#fff;text-decoration:underline' target='_blank' href='https://wwads.cn/page/end-user-privacy'>并不跟踪您的隐私</a>，为了支持本站的长期运营，请将我们的网站 <a style='color: #fff;text-decoration:underline' target='_blank' href='https://wwads.cn/page/whitelist-wwads'>加入广告拦截器的白名单</a>。\";\n    document.getElementsByTagName(\"body\")[0].appendChild(adBlockDetected_div);\n    // add a close button to the right side of the div\n    var adBlockDetected_close = document.createElement(\"div\");\n    adBlockDetected_close.style.cssText =\n      \"position: absolute; top: 0; right: 10px; width: 30px; height: 30px; background: #fc6600; color: #fff; z-index: 9999999999; line-height: 30px; cursor: pointer;\";\n    adBlockDetected_close.innerHTML = \"×\";\n    adBlockDetected_div.appendChild(adBlockDetected_close);\n    // add a click event to the close button\n    adBlockDetected_close.onclick = function () {\n      this.parentNode.parentNode.removeChild(this.parentNode);\n    };\n  }\n\n  function docReady(t) {\n    \"complete\" === document.readyState || \"interactive\" === document.readyState\n      ? setTimeout(t, 1)\n      : document.addEventListener(\"DOMContentLoaded\", t);\n  }\n\n  //check if wwads' fire function was blocked after document is ready with 3s timeout (waiting the ad loading)\n  docReady(function () {\n    setTimeout(function () {\n      if (window._AdBlockInit === undefined) {\n        ABDetected();\n      }\n    }, 3000);\n  });\n});\n"
  },
  {
    "path": "frontend/web/js/nav.js",
    "content": "/**\n * Created by ruzuojun on 2015/6/26.\n */\n\n// $(\".pinned\").pin({containerSelector: \".container\", minWidth: 940});\n// $(function () {\n//     $('[data-toggle=\"tooltip\"]').tooltip()\n// })"
  },
  {
    "path": "frontend/web/js/topic.js",
    "content": "jQuery(function ($) {\n\n    //赞, 踩, 收藏 等操作\n    $(document).on('click', '[data-do]', function (e) {\n        var _this = $(this),\n            _id = _this.data('id'),\n            _do = _this.data('do'),\n            _type = _this.data('type');\n        if (_this.is('a')) e.preventDefault();\n        $.ajax({\n            url: '/member/' + [_do, _type, _id].join('/'),\n            success: function (result) {\n                if (result.type != 'success') {\n                    return alert(result.message);\n                }\n                //修改记数\n                var num = _this.find('span'),\n                    numValue = parseInt(num.html()),\n                    active = _this.hasClass('active');\n                _this.toggleClass('active');\n                if (num.length) {\n                    num.html(numValue + (active ? -1 : 1));\n                }\n                if ($.inArray(_do, ['like', 'hate']) >= 0) {\n                    _this.siblings('[data-do=like],[data-do=hate]').each(function () {\n                        var __this = $(this),\n                            __do = __this.data('do'),\n                            __id = __this.data('id'),\n                            __active = __this.hasClass('active');\n                        if (__id != _id) return; // 同一个话题或回复触发\n\n                        __this.toggleClass('active', __do == _do);\n\n                        var _num = __this.find('span')\n                        _numValue = parseInt(_num.html());\n                        if (_num.length) {\n                            _num.html(_numValue + (__do != _do ? (_numValue > 0 && __active ? -1 : 0) : 1));\n                        }\n                    });\n                }\n            }\n        });\n    });\n});"
  },
  {
    "path": "frontend/web/robots.txt",
    "content": "User-agent: *\nDisallow:"
  },
  {
    "path": "frontend/web/uploads/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "frontend/widgets/Alert.php",
    "content": "<?php\n/**\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\nnamespace frontend\\widgets;\n\n/**\n * Alert widget renders a message from session flash. All flash messages are displayed\n * in the sequence they were assigned using setFlash. You can set message as following:\n *\n * ```php\n * \\Yii::$app->getSession()->setFlash('error', 'This is the message');\n * \\Yii::$app->getSession()->setFlash('success', 'This is the message');\n * \\Yii::$app->getSession()->setFlash('info', 'This is the message');\n * ```\n *\n * Multiple messages could be set as follows:\n *\n * ```php\n * \\Yii::$app->getSession()->setFlash('error', ['Error 1', 'Error 2']);\n * ```\n *\n * @author Kartik Visweswaran <kartikv2@gmail.com>\n * @author Alexander Makarov <sam@rmcreative.ru>\n */\nclass Alert extends \\yii\\bootstrap\\Widget\n{\n    /**\n     * @var array the alert types configuration for the flash messages.\n     * This array is setup as $key => $value, where:\n     * - $key is the name of the session flash variable\n     * - $value is the bootstrap alert type (i.e. danger, success, info, warning)\n     */\n    public $alertTypes = [\n        'error'   => 'alert-danger',\n        'danger'  => 'alert-danger',\n        'success' => 'alert-success',\n        'info'    => 'alert-info',\n        'warning' => 'alert-warning'\n    ];\n\n    /**\n     * @var array the options for rendering the close button tag.\n     */\n    public $closeButton = [];\n\n    public function init()\n    {\n        parent::init();\n\n        $session = \\Yii::$app->getSession();\n        $flashes = $session->getAllFlashes();\n        $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : '';\n\n        foreach ($flashes as $type => $data) {\n            if (isset($this->alertTypes[$type])) {\n                $data = (array) $data;\n                foreach ($data as $message) {\n                    /* initialize css class for each alert box */\n                    $this->options['class'] = $this->alertTypes[$type] . $appendCss;\n\n                    /* assign unique id to each alert box */\n                    $this->options['id'] = $this->getId() . '-' . $type;\n\n                    echo \\yii\\bootstrap\\Alert::widget([\n                        'body' => $message,\n                        'closeButton' => $this->closeButton,\n                        'options' => $this->options,\n                    ]);\n                }\n\n                $session->removeFlash($type);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "frontend/widgets/Connect.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-01-24 21:37:24\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-01-24 22:19:04\n */\n\nnamespace frontend\\widgets;\n\nuse yii\\authclient\\ClientInterface;\nuse yii\\authclient\\widgets\\AuthChoice;\nuse yii\\authclient\\widgets\\AuthChoiceAsset;\nuse yii\\helpers\\Html;\nuse yii\\helpers\\Url;\n\nclass Connect extends AuthChoice\n{\n    /**\n     * @var array|null An array of user's accounts\n     */\n    public $accounts;\n\n    /**\n     * @inheritdoc\n     */\n    public $options = [];\n\n    /**\n     * @inheritdoc\n     */\n    public function init()\n    {\n        AuthChoiceAsset::register(\\Yii::$app->view);\n        if ($this->popupMode) {\n            \\Yii::$app->view->registerJs(\"\\$('#\" . $this->getId() . \"').authchoice();\");\n        }\n        $this->options['id'] = $this->getId();\n        echo Html::beginTag('div', $this->options);\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function createClientUrl($provider)\n    {\n        if ($this->isConnected($provider)) {\n            return Url::to(['/user/setting/disconnect', 'id' => $this->accounts[$provider->getId()]->id]);\n        } else {\n            return parent::createClientUrl($provider);\n        }\n    }\n\n    /**\n     * Checks if provider already connected to user.\n     *\n     * @param ClientInterface $provider\n     * @return bool\n     */\n    public function isConnected(ClientInterface $provider)\n    {\n        return $this->accounts != null && isset($this->accounts[$provider->getId()]);\n    }\n}"
  },
  {
    "path": "frontend/widgets/Nav.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/23 下午4:13\n * description:\n */\n\nnamespace frontend\\widgets;\n\nuse common\\services\\UserService;\n\nclass Nav extends \\yii\\bootstrap\\Widget\n{\n\n    public function run()\n    {\n        $notifyCount = UserService::findNotifyCount();\n\n        return $this->render('nav', [\n            'notifyCount' => $notifyCount,\n        ]);\n    }\n}"
  },
  {
    "path": "frontend/widgets/NewestPost.php",
    "content": "<?php\n/**\n * @Author: forecho\n * @Date:   2015-02-27 11:08:56\n * @Last Modified by:   forecho\n * @Last Modified time: 2015-02-27 11:38:44\n */\n\nnamespace frontend\\widgets;\n\nuse common\\models\\Post;\n\nclass NewestPost extends \\yii\\bootstrap\\Widget\n{\n\tpublic $options = [];\n\n    public function getPost()\n    {\n        return $model = Post::find()\n            ->where(['status' => 1])\n            ->orderBy(['order' => SORT_ASC, 'created_at' => SORT_DESC])\n            ->limit(3)->all();\n    }\n}\n"
  },
  {
    "path": "frontend/widgets/Node.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/25 下午1:42\n * description:\n */\n\nnamespace frontend\\widgets;\n\nuse common\\models\\PostMeta;\n\nclass Node extends \\yii\\bootstrap\\Widget\n{\n    public function run()\n    {\n        $nodes = PostMeta::getNodes();\n\n        return $this->render('node', [\n            'nodes' => $nodes\n        ]);\n    }\n}"
  },
  {
    "path": "frontend/widgets/Panel.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/18 下午4:13\n * description:\n */\n\nnamespace frontend\\widgets;\n\nclass Panel extends \\yii\\bootstrap\\Widget\n{\n    public $items = [];\n    public $title = '';\n\n    public function run()\n    {\n        $model = [\n            'items' => $this->items,\n            'title' => $this->title,\n        ];\n\n        return $this->render('panel', [\n            'model' => $model,\n        ]);\n    }\n}"
  },
  {
    "path": "frontend/widgets/TopicSidebar.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/18 下午4:13\n * description:\n */\n\nnamespace frontend\\widgets;\n\nuse common\\helpers\\Arr;\nuse common\\models\\PostMeta;\nuse common\\models\\RightLink;\nuse frontend\\modules\\topic\\models\\Topic;\nuse frontend\\modules\\user\\models\\Donate;\nuse yii\\helpers\\ArrayHelper;\nuse yii\\helpers\\Url;\n\nclass TopicSidebar extends \\yii\\bootstrap\\Widget\n{\n    public $type = 'node';\n    public $node;\n    public $tags;\n\n    public function init()\n    {\n        parent::init();\n    }\n\n    public function run()\n    {\n        $tipsModel = ArrayHelper::map(\n            RightLink::find()->where(['type' => RightLink::RIGHT_LINK_TYPE_TIPS])->all(),\n            'content',\n            'title'\n        );\n        $tips = $tipsModel ? array_rand($tipsModel) : [];\n\n        $recommendResources = ArrayHelper::map(\n            RightLink::find()->where(['type' => RightLink::RIGHT_LINK_TYPE_RSOURCES])->all(),\n            'title',\n            'url'\n        );\n\n        $links = RightLink::find()->where(['type' => RightLink::RIGHT_LINK_TYPE_LINKS])->all();\n\n        $sameTopics = [];\n        if ($this->node) {\n            $sameTopics = ArrayHelper::map(\n                Topic::find()\n                    ->where('status >= :status', [':status' => Topic::STATUS_ACTIVE])\n                    ->andWhere(['post_meta_id' => $this->node->id, 'type' => 'topic'])\n                    ->limit(200)->all(),\n                'title',\n                function ($e) {\n                    return Url::to(['/topic/default/view', 'id' => $e->id]);\n                }\n            );\n            if (count($sameTopics) > 10) {\n                $sameTopics = Arr::arrayRandomAssoc($sameTopics, 10);\n            }\n        }\n\n        return $this->render('topicSidebar', [\n            'category' => PostMeta::blogCategory(),\n            'config' => ['type' => $this->type, 'node' => $this->node],\n            'sameTopics' => $sameTopics,\n            'tips' => $tips,\n            'recommendResources' => $recommendResources,\n            'links' => $links,\n        ]);\n    }\n}"
  },
  {
    "path": "frontend/widgets/views/nav.php",
    "content": "<?php\r\n/**\r\n * author     : forecho <caizh@snsshop.com>\r\n * createTime : 2015/4/23 17:23\r\n * description:\r\n */\r\nuse rmrevin\\yii\\fontawesome\\FA;\r\nuse yii\\bootstrap\\Nav;\r\nuse yii\\bootstrap\\NavBar;\r\nuse yii\\helpers\\Html;\r\n\r\n$module = Yii::$app->controller->module->id;\r\n$action = Yii::$app->controller->action->id;\r\n$tag = Yii::$app->request->getQueryParam('tag');\r\n$keyword = htmlspecialchars(Yii::$app->request->getQueryParam('keyword'));\r\n\r\n$node = Yii::$app->request->getQueryParam('node');\r\n$topicActive = ($module == 'topic' && !$tag && $node != 'jobs') ? true : false;\r\n$tweetActive = ($module == 'tweet') ? true : false;\r\n$topicTagsActive = $action == 'tags' || ($module == 'topic' && $tag) ? true : false;\r\n$navActive = ($module == 'nav') ? true : false;\r\n\r\n$jobsActive = ($node == 'jobs') ? true : false;\r\n\r\nNavBar::begin([\r\n//     'brandLabel' => Html::img('/images/logo.png'),\r\n    'brandLabel' => 'Get√Yii',\r\n    'brandUrl' => Yii::$app->homeUrl,\r\n    'options' => [\r\n        'class' => 'navbar-white br0 navbar-fixed-top navbar',\r\n    ],\r\n]);\r\necho Nav::widget([\r\n    'options' => ['class' => 'nav navbar-nav '],\r\n    'items' => [\r\n        ['label' => '社区', 'url' => ['/topic'], 'active' => $topicActive],\r\n        ['label' => '招聘', 'url' => ['/topic/default/index', 'node' => 'jobs'], 'active' => $jobsActive],\r\n        ['label' => '动弹', 'url' => ['/tweet'], 'active' => $tweetActive],\r\n        ['label' => '标签', 'url' => ['/site/tags'], 'active' => $topicTagsActive],\r\n//        ['label' => '新手入门', 'url' => ['/site/getstart']],\r\n        ['label' => '酷站', 'url' => ['/nav'], 'active' => $navActive],\r\n\r\n    ],\r\n    'encodeLabels' => false\r\n]);\r\nif (Yii::$app->params['setting']['xunsearch']) {\r\n    echo '<form class=\"navbar-form navbar-left\" role=\"search\" action=\"/search\" method=\"get\">\r\n                <div class=\"form-group\">\r\n                    <input type=\"text\" value=\"' . $keyword . '\" name=\"keyword\" class=\"form-control search_input\" id=\"navbar-search\" placeholder=\"搜索...\" data-placement=\"bottom\" data-content=\"请输入要搜索的关键词！\">\r\n                </div>\r\n            </form>';\r\n}\r\n\r\n\r\nif (Yii::$app->user->isGuest) {\r\n    $menuItems[] = ['label' => '注册', 'url' => ['/site/signup']];\r\n    $menuItems[] = ['label' => '登录', 'url' => ['/site/login']];\r\n} else {\r\n    // 撰写\r\n    $menuItems[] = [\r\n        'label' => Html::tag('i', '', ['class' => 'fa fa-bell']) . Html::tag('span', $notifyCount ? $notifyCount : null),\r\n        'url' => ['/notification/index'],\r\n        'linkOptions' => ['class' => $notifyCount ? 'new' : null],\r\n        'options' => ['class' => 'notification-count'],\r\n    ];\r\n\r\n    // 个人中心\r\n    $menuItems[] = [\r\n        'label' => Yii::$app->user->identity->username,\r\n        'items' => [\r\n            ['label' => '我的主页', 'url' => ['/user/default']],\r\n            ['label' => '帐号设置', 'url' => ['/user/setting/profile']],\r\n            ['label' => '退出', 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post']]\r\n        ]\r\n    ];\r\n}\r\n\r\necho Nav::widget([\r\n    'encodeLabels' => false,\r\n    'options' => ['class' => 'nav navbar-nav navbar-right'],\r\n    'items' => $menuItems,\r\n    'activateParents' => true,\r\n]);\r\nNavBar::end();\r\n"
  },
  {
    "path": "frontend/widgets/views/node.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/25 下午1:44\n * description:\n */\n/** @var \\common\\models\\PostMeta[] $nodes */\n?>\n<?php if (isset($nodes) && !empty($nodes)) : ?>\n    <div class=\"panel panel-default node-panel\">\n        <div class=\"panel-heading\">\n            <h3 class=\"panel-title text-center\">节点导航</h3>\n        </div>\n\n        <div class=\"panel-body p0\">\n            <dl class=\"dl-horizontal node-box mb0\">\n                <?php foreach ($nodes as $key => $value): ?>\n                    <dt><?= $value->name ?></dt>\n                    <dd>\n                        <ul class=\"list-inline\">\n                            <?php foreach ($value->children as $node): ?>\n                                <li><?= \\yii\\helpers\\Html::a($node->name, ['/topic/default/index', 'node' => $node->alias]) ?></li>\n                            <?php endforeach ?>\n                        </ul>\n                    </dd>\n                    <div class=\"divider\"></div>\n                <?php endforeach ?>\n            </dl>\n        </div>\n    </div>\n<?php endif ?>\n"
  },
  {
    "path": "frontend/widgets/views/panel.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/18 下午4:16\n * description:\n */\nuse yii\\helpers\\Html;\n\n?>\n<?php if ($model): ?>\n    <div class=\"panel panel-default corner-radius\">\n        <div class=\"panel-heading text-center\">\n            <h3 class=\"panel-title\"><?= $model['title']?></h3>\n        </div>\n        <div class=\"panel-body side-bar\">\n            <ul class=\"list\">\n                <?php foreach ($model['items'] as $key => $value) {\n                    echo Html::tag('li', Html::a(Html::encode($key), $value));\n                } ?>\n            </ul>\n        </div>\n    </div>\n<?php endif ?>\n\n"
  },
  {
    "path": "frontend/widgets/views/topicSidebar.php",
    "content": "<?php\n/**\n * author     : forecho <caizhenghai@gmail.com>\n * createTime : 15/4/18 下午 4:16\n * description:\n */\n\nuse yii\\helpers\\Html;\n\n/** @var array $sameTopics */\n/** @var array $config */\n/** @var array $recommendResources */\n/** @var string $tips */\n\n$node = $config['node'];\n?>\n<div class=\"col-md-3 side-bar p0\">\n\n    <div class=\"<?= (request('id')) ? 'p-fixed' : null; ?>\">\n\n        <?php if ($config['type'] != 'create'): ?>\n            <div class=\"panel panel-default corner-radius\">\n\n                <?php if ($node): ?>\n                    <div class=\"panel-heading text-center\">\n                        <h3 class=\"panel-title\"><?= $node->name ?></h3>\n                    </div>\n                <?php endif ?>\n\n                <div class=\"panel-body text-center\">\n                    <div class=\"btn-group\">\n                        <?= Html::a(\n                            \\Yii::t('app', 'New Topic'),\n                            ['/topic/default/create', 'id' => 'id'],\n                            ['class' => 'btn btn-success']\n                        ) ?>\n                    </div>\n                </div>\n            </div>\n        <?php endif ?>\n\n        <div class=\"panel panel-default corner-radius\">\n            <div class=\"panel-heading text-center\">\n                <h3 class=\"panel-title\"><?= \\Yii::t('app', 'Tips and Tricks'); ?></h3>\n            </div>\n            <div class=\"panel-body\">\n                <?= $tips ? \\yii\\helpers\\Markdown::process($tips, 'gfm') : ''; ?>\n            </div>\n        </div>\n\n        <div class=\"panel panel-default corner-radius\">\n            <div class=\"wwads-cn wwads-vertical\" data-id=\"83\" style=\"max-width:290.5px;background-color:#fff\"></div>\n        </div>\n\n        <?php if (!$node) {\n            echo \\frontend\\widgets\\Panel::widget([\n                'title' => \\Yii::t('app', 'Recomended Resources'),\n                'items' => $recommendResources,\n            ]);\n        } ?>\n\n        <?php if ($node) {\n            echo \\frontend\\widgets\\Panel::widget([\n                'title' => \\Yii::t('app', 'Same Node Topics'),\n                'items' => $sameTopics,\n            ]);\n        } ?>\n\n        <?php \\frontend\\widgets\\Panel::widget([\n            'title' => \\Yii::t('app', 'Site Status'),\n            'items' => [],\n        ]) ?>\n\n        <?php if (!$config['node'] && !empty($links)): ?>\n            <div class=\"panel panel-default corner-radius\">\n                <div class=\"panel-heading text-center\">\n                    <h3 class=\"panel-title\"><?= \\Yii::t('app', 'Links') ?></h3>\n                </div>\n                <div class=\"panel-body text-center\" style=\"padding-top: 5px;\">\n                    <?php foreach ($links as $key => $value) {\n                        echo Html::a(\n                            Html::img($value->image),\n                            $value->url,\n                            ['class' => 'list-group-item', 'target' => '_blank', 'title' => $value->title]\n                        );\n                    } ?>\n                </div>\n            </div>\n        <?php endif ?>\n\n    </div>\n</div>\n<div class=\"clearfix\"></div>\n"
  },
  {
    "path": "init",
    "content": "#!/usr/bin/env php\n<?php\n/**\n * Yii Application Initialization Tool\n *\n * In order to run in non-interactive mode:\n *\n * init --env=Development --overwrite=n\n *\n * @author Alexander Makarov <sam@rmcreative.ru>\n *\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\nif (!extension_loaded('openssl')) {\n    die('The OpenSSL PHP extension is required by Yii2.');\n}\n\n$params = getParams();\n$root = str_replace('\\\\', '/', __DIR__);\n$envs = require(\"$root/environments/index.php\");\n$envNames = array_keys($envs);\n\necho \"Yii Application Initialization Tool v1.0\\n\\n\";\n\n$envName = null;\nif (empty($params['env']) || $params['env'] === '1') {\n    echo \"Which environment do you want the application to be initialized in?\\n\\n\";\n    foreach ($envNames as $i => $name) {\n        echo \"  [$i] $name\\n\";\n    }\n    echo \"\\n  Your choice [0-\" . (count($envs) - 1) . ', or \"q\" to quit] ';\n    $answer = trim(fgets(STDIN));\n\n    if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {\n        echo \"\\n  Quit initialization.\\n\";\n        exit(0);\n    }\n\n    if (isset($envNames[$answer])) {\n        $envName = $envNames[$answer];\n    }\n} else {\n    $envName = $params['env'];\n}\n\nif (!in_array($envName, $envNames)) {\n    $envsList = implode(', ', $envNames);\n    echo \"\\n  $envName is not a valid environment. Try one of the following: $envsList. \\n\";\n    exit(2);\n}\n\n$env = $envs[$envName];\n\nif (empty($params['env'])) {\n    echo \"\\n  Initialize the application under '{$envNames[$answer]}' environment? [yes|no] \";\n    $answer = trim(fgets(STDIN));\n    if (strncasecmp($answer, 'y', 1)) {\n        echo \"\\n  Quit initialization.\\n\";\n        exit(0);\n    }\n}\n\necho \"\\n  Start initialization ...\\n\\n\";\n$files = getFileList(\"$root/environments/{$env['path']}\");\nif (isset($env['skipFiles'])) {\n    $skipFiles = $env['skipFiles'];\n    array_walk($skipFiles, function (&$value) use ($env, $root) {\n        $value = \"$root/$value\";\n    });\n    $files = array_diff($files, array_intersect_key($env['skipFiles'], array_filter($skipFiles, 'file_exists')));\n}\n$all = false;\nforeach ($files as $file) {\n    if (!copyFile($root, \"environments/{$env['path']}/$file\", $file, $all, $params)) {\n        break;\n    }\n}\n\n$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable', 'createSymlink'];\nforeach ($callbacks as $callback) {\n    if (!empty($env[$callback])) {\n        $callback($root, $env[$callback]);\n    }\n}\n\necho \"\\n  ... initialization completed.\\n\\n\";\n\nfunction getFileList($root, $basePath = '')\n{\n    $files = [];\n    $handle = opendir($root);\n    while (($path = readdir($handle)) !== false) {\n        if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') {\n            continue;\n        }\n        $fullPath = \"$root/$path\";\n        $relativePath = $basePath === '' ? $path : \"$basePath/$path\";\n        if (is_dir($fullPath)) {\n            $files = array_merge($files, getFileList($fullPath, $relativePath));\n        } else {\n            $files[] = $relativePath;\n        }\n    }\n    closedir($handle);\n    return $files;\n}\n\nfunction copyFile($root, $source, $target, &$all, $params)\n{\n    if (!is_file($root . '/' . $source)) {\n        echo \"       skip $target ($source not exist)\\n\";\n        return true;\n    }\n    if (is_file($root . '/' . $target)) {\n        if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {\n            echo \"  unchanged $target\\n\";\n            return true;\n        }\n        if ($all) {\n            echo \"  overwrite $target\\n\";\n        } else {\n            echo \"      exist $target\\n\";\n            echo \"            ...overwrite? [Yes|No|All|Quit] \";\n\n\n            $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));\n            if (!strncasecmp($answer, 'q', 1)) {\n                return false;\n            } else {\n                if (!strncasecmp($answer, 'y', 1)) {\n                    echo \"  overwrite $target\\n\";\n                } else {\n                    if (!strncasecmp($answer, 'a', 1)) {\n                        echo \"  overwrite $target\\n\";\n                        $all = true;\n                    } else {\n                        echo \"       skip $target\\n\";\n                        return true;\n                    }\n                }\n            }\n        }\n        file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));\n        return true;\n    }\n    echo \"   generate $target\\n\";\n    @mkdir(dirname($root . '/' . $target), 0777, true);\n    file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));\n    return true;\n}\n\nfunction getParams()\n{\n    $rawParams = [];\n    if (isset($_SERVER['argv'])) {\n        $rawParams = $_SERVER['argv'];\n        array_shift($rawParams);\n    }\n\n    $params = [];\n    foreach ($rawParams as $param) {\n        if (preg_match('/^--(\\w+)(=(.*))?$/', $param, $matches)) {\n            $name = $matches[1];\n            $params[$name] = isset($matches[3]) ? $matches[3] : true;\n        } else {\n            $params[] = $param;\n        }\n    }\n    return $params;\n}\n\nfunction setWritable($root, $paths)\n{\n    foreach ($paths as $writable) {\n        if (is_dir(\"$root/$writable\")) {\n            echo \"      chmod 0777 $writable\\n\";\n            @chmod(\"$root/$writable\", 0777);\n        } else {\n            echo \"\\n  Error. Directory $writable does not exist. \\n\";\n        }\n    }\n}\n\nfunction setExecutable($root, $paths)\n{\n    foreach ($paths as $executable) {\n        echo \"      chmod 0755 $executable\\n\";\n        @chmod(\"$root/$executable\", 0755);\n    }\n}\n\nfunction setCookieValidationKey($root, $paths)\n{\n    foreach ($paths as $file) {\n        echo \"   generate cookie validation key in $file\\n\";\n        $file = $root . '/' . $file;\n        $length = 32;\n        $bytes = openssl_random_pseudo_bytes($length);\n        $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');\n        $content = preg_replace('/((\"|\\')cookieValidationKey(\"|\\')\\s*=>\\s*)(\"\"|\\'\\')/', \"\\\\1'$key'\",\n            file_get_contents($file));\n        file_put_contents($file, $content);\n    }\n}\n\nfunction createSymlink($root, $links)\n{\n    foreach ($links as $link => $target) {\n        echo \"      symlink \" . $root . \"/\" . $target . \" \" . $root . \"/\" . $link . \"\\n\";\n        //first removing folders to avoid errors if the folder already exists\n        @rmdir($root . \"/\" . $link);\n        @symlink($root . \"/\" . $target, $root . \"/\" . $link);\n    }\n}\n"
  },
  {
    "path": "init.bat",
    "content": "@echo off\n\nrem -------------------------------------------------------------\nrem  Yii command line init script for Windows.\nrem\nrem  @author Qiang Xue <qiang.xue@gmail.com>\nrem  @link http://www.yiiframework.com/\nrem  @copyright Copyright (c) 2008 Yii Software LLC\nrem  @license http://www.yiiframework.com/license/\nrem -------------------------------------------------------------\n\n@setlocal\n\nset YII_PATH=%~dp0\n\nif \"%PHP_COMMAND%\" == \"\" set PHP_COMMAND=php.exe\n\n\"%PHP_COMMAND%\" \"%YII_PATH%init\" %*\n\n@endlocal\n"
  },
  {
    "path": "requirements.php",
    "content": "<?php\n/**\n * Application requirement checker script.\n *\n * In order to run this script use the following console command:\n * php requirements.php\n *\n * In order to run this script from the web, you should copy it to the web root.\n * If you are using Linux you can create a hard link instead, using the following command:\n * ln requirements.php ../requirements.php\n */\n\n// you may need to adjust this path to the correct Yii framework path\n$frameworkPath = dirname(__FILE__) . '/vendor/yiisoft/yii2';\n\nif (!is_dir($frameworkPath)) {\n    echo '<h1>Error</h1>';\n    echo '<p><strong>The path to yii framework seems to be incorrect.</strong></p>';\n    echo '<p>You need to install Yii framework via composer or adjust the framework path in file <abbr title=\"' . __FILE__ . '\">' . basename(__FILE__) . '</abbr>.</p>';\n    echo '<p>Please refer to the <abbr title=\"' . dirname(__FILE__) . '/README.md\">README</abbr> on how to install Yii.</p>';\n}\n\nrequire_once($frameworkPath . '/requirements/YiiRequirementChecker.php');\n$requirementsChecker = new YiiRequirementChecker();\n\n$gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.';\n$gdOK = $imagickOK = false;\n\nif (extension_loaded('imagick')) {\n    $imagick = new Imagick();\n    $imagickFormats = $imagick->queryFormats('PNG');\n    if (in_array('PNG', $imagickFormats)) {\n        $imagickOK = true;\n    } else {\n        $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.';\n    }\n}\n\nif (extension_loaded('gd')) {\n    $gdInfo = gd_info();\n    if (!empty($gdInfo['FreeType Support'])) {\n        $gdOK = true;\n    } else {\n        $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.';\n    }\n}\n\n/**\n * Adjust requirements according to your application specifics.\n */\n$requirements = array(\n    // Database :\n    array(\n        'name' => 'PDO extension',\n        'mandatory' => true,\n        'condition' => extension_loaded('pdo'),\n        'by' => 'All DB-related classes',\n    ),\n    array(\n        'name' => 'PDO SQLite extension',\n        'mandatory' => false,\n        'condition' => extension_loaded('pdo_sqlite'),\n        'by' => 'All DB-related classes',\n        'memo' => 'Required for SQLite database.',\n    ),\n    array(\n        'name' => 'PDO MySQL extension',\n        'mandatory' => false,\n        'condition' => extension_loaded('pdo_mysql'),\n        'by' => 'All DB-related classes',\n        'memo' => 'Required for MySQL database.',\n    ),\n    array(\n        'name' => 'PDO PostgreSQL extension',\n        'mandatory' => false,\n        'condition' => extension_loaded('pdo_pgsql'),\n        'by' => 'All DB-related classes',\n        'memo' => 'Required for PostgreSQL database.',\n    ),\n    // Cache :\n    array(\n        'name' => 'Memcache extension',\n        'mandatory' => false,\n        'condition' => extension_loaded('memcache') || extension_loaded('memcached'),\n        'by' => '<a href=\"http://www.yiiframework.com/doc-2.0/yii-caching-memcache.html\">MemCache</a>',\n        'memo' => extension_loaded('memcached') ? 'To use memcached set <a href=\"http://www.yiiframework.com/doc-2.0/yii-caching-memcache.html#$useMemcached-detail\">MemCache::useMemcached</a> to <code>true</code>.' : ''\n    ),\n    array(\n        'name' => 'APC extension',\n        'mandatory' => false,\n        'condition' => extension_loaded('apc'),\n        'by' => '<a href=\"http://www.yiiframework.com/doc-2.0/yii-caching-apccache.html\">ApcCache</a>',\n    ),\n    // CAPTCHA:\n    array(\n        'name' => 'GD PHP extension with FreeType support',\n        'mandatory' => false,\n        'condition' => $gdOK,\n        'by' => '<a href=\"http://www.yiiframework.com/doc-2.0/yii-captcha-captcha.html\">Captcha</a>',\n        'memo' => $gdMemo,\n    ),\n    array(\n        'name' => 'ImageMagick PHP extension with PNG support',\n        'mandatory' => false,\n        'condition' => $imagickOK,\n        'by' => '<a href=\"http://www.yiiframework.com/doc-2.0/yii-captcha-captcha.html\">Captcha</a>',\n        'memo' => $imagickMemo,\n    ),\n    // PHP ini :\n    'phpExposePhp' => array(\n        'name' => 'Expose PHP',\n        'mandatory' => false,\n        'condition' => $requirementsChecker->checkPhpIniOff(\"expose_php\"),\n        'by' => 'Security reasons',\n        'memo' => '\"expose_php\" should be disabled at php.ini',\n    ),\n    'phpAllowUrlInclude' => array(\n        'name' => 'PHP allow url include',\n        'mandatory' => false,\n        'condition' => $requirementsChecker->checkPhpIniOff(\"allow_url_include\"),\n        'by' => 'Security reasons',\n        'memo' => '\"allow_url_include\" should be disabled at php.ini',\n    ),\n    'phpSmtp' => array(\n        'name' => 'PHP mail SMTP',\n        'mandatory' => false,\n        'condition' => strlen(ini_get('SMTP')) > 0,\n        'by' => 'Email sending',\n        'memo' => 'PHP mail SMTP server required',\n    ),\n);\n$requirementsChecker->checkYii()->check($requirements)->render();\n"
  },
  {
    "path": "tests/README.md",
    "content": "This directory contains various tests for the advanced applications.\n\nTests in `codeception` directory are developed with [Codeception PHP Testing Framework](http://codeception.com/).\n\nAfter creating and setting up the advanced application, follow these steps to prepare for the tests:\n\n1. Install Codeception if it's not yet installed:\n\n   ```\n   composer global require \"codeception/codeception=2.0.*\" \"codeception/specify=*\" \"codeception/verify=*\"\n   ```\n\n   If you've never used Composer for global packages run `composer global status`. It should output:\n\n   ```\n   Changed current directory to <directory>\n   ```\n\n   Then add `<directory>/vendor/bin` to you `PATH` environment variable. Now you're able to use `codecept` from command\n   line globally.\n\n2. Install faker extension by running the following from template root directory where `composer.json` is:\n\n   ```\n   composer require --dev yiisoft/yii2-faker:*\n   ```\n\n3. Create `yii2_advanced_tests` database then update it by applying migrations:\n\n   ```\n   codeception/bin/yii migrate\n   ```\n\n4. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in\n   webserver. In the root directory where `common`, `frontend` etc. are execute the following:\n\n   ```\n   php -S localhost:8080\n   ```\n\n5. Now you can run the tests with the following commands, assuming you are in the `tests/codeception` directory:\n\n   ```\n   # frontend tests\n   cd frontend\n   codecept build\n   codecept run\n   \n   # backend tests\n   \n   cd backend\n   codecept build\n   codecept run\n    \n   # etc.\n   ```\n\n  If you already have run `codecept build` for each application, you can skip that step and run all tests by a single `codecept run`.\n"
  },
  {
    "path": "tests/codeception/_output/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "tests/codeception/backend/.gitignore",
    "content": "# these files are auto generated by codeception build\n/unit/UnitTester.php\n/functional/FunctionalTester.php\n/acceptance/AcceptanceTester.php\n"
  },
  {
    "path": "tests/codeception/backend/_bootstrap.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n\ndefined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(__DIR__))));\n\ndefined('YII_BACKEND_TEST_ENTRY_URL') or define('YII_BACKEND_TEST_ENTRY_URL', \\Codeception\\Configuration::config()['config']['test_entry_url']);\ndefined('YII_TEST_BACKEND_ENTRY_FILE') or define('YII_TEST_BACKEND_ENTRY_FILE', YII_APP_BASE_PATH . '/backend/web/index-test.php');\n\nrequire_once(YII_APP_BASE_PATH . '/vendor/autoload.php');\nrequire_once(YII_APP_BASE_PATH . '/vendor/yiisoft/yii2/Yii.php');\nrequire_once(YII_APP_BASE_PATH . '/common/config/bootstrap.php');\nrequire_once(YII_APP_BASE_PATH . '/backend/config/bootstrap.php');\n\n// set correct script paths\n\n// the entry script file path for functional and acceptance tests\n$_SERVER['SCRIPT_FILENAME'] = YII_TEST_BACKEND_ENTRY_FILE;\n$_SERVER['SCRIPT_NAME'] = YII_BACKEND_TEST_ENTRY_URL;\n$_SERVER['SERVER_NAME'] = 'localhost';\n\nYii::setAlias('@tests', dirname(dirname(__DIR__)));\n"
  },
  {
    "path": "tests/codeception/backend/_output/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "tests/codeception/backend/acceptance/LoginCept.php",
    "content": "<?php\n\nuse tests\\codeception\\backend\\AcceptanceTester;\nuse tests\\codeception\\common\\_pages\\LoginPage;\n\n$I = new AcceptanceTester($scenario);\n$I->wantTo('ensure login page works');\n\n$loginPage = LoginPage::openBy($I);\n\n$I->amGoingTo('submit login form with no data');\n$loginPage->login('', '');\n$I->expectTo('see validations errors');\n$I->see('Username cannot be blank.', '.help-block');\n$I->see('Password cannot be blank.', '.help-block');\n\n$I->amGoingTo('try to login with wrong credentials');\n$I->expectTo('see validations errors');\n$loginPage->login('admin', 'wrong');\n$I->expectTo('see validations errors');\n$I->see('Incorrect username or password.', '.help-block');\n\n$I->amGoingTo('try to login with correct credentials');\n$loginPage->login('erau', 'password_0');\n$I->expectTo('see that user is logged');\n$I->seeLink('Logout (erau)');\n$I->dontSeeLink('Login');\n$I->dontSeeLink('Signup');\n/** Uncomment if using WebDriver\n * $I->click('Logout (erau)');\n * $I->dontSeeLink('Logout (erau)');\n * $I->seeLink('Login');\n */\n"
  },
  {
    "path": "tests/codeception/backend/acceptance/_bootstrap.php",
    "content": "<?php\nnew yii\\web\\Application(require(dirname(dirname(__DIR__)) . '/config/backend/acceptance.php'));\n"
  },
  {
    "path": "tests/codeception/backend/acceptance.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for acceptance tests.\n# perform tests in browser using the Selenium-like tools.\n# powered by Mink (http://mink.behat.org).\n# (tip: that's what your customer will see).\n# (tip: test your ajax and javascript by one of Mink drivers).\n\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n\nclass_name: AcceptanceTester\nmodules:\n    enabled:\n        - PhpBrowser\n        - tests\\codeception\\common\\_support\\FixtureHelper\n# you can use WebDriver instead of PhpBrowser to test javascript and ajax.\n# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium\n# \"restart\" option is used by the WebDriver to start each time per test-file new session and cookies,\n# it is useful if you want to login in your app in each test.\n#        - WebDriver\n    config:\n        PhpBrowser:\n            url: 'http://localhost:8080'\n#        WebDriver:\n#            url: 'http://localhost'\n#            browser: firefox\n#            restart: true\n"
  },
  {
    "path": "tests/codeception/backend/codeception.yml",
    "content": "namespace: tests\\codeception\\backend\nactor: Tester\npaths:\n    tests: .\n    log: _output\n    data: _data\n    helpers: _support\nsettings:\n    bootstrap: _bootstrap.php\n    suite_class: \\PHPUnit_Framework_TestSuite\n    colors: true\n    memory_limit: 1024M\n    log: true\nconfig:\n    # the entry script URL (without host info) for functional and acceptance tests\n    # PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL\n    test_entry_url: /backend/web/index-test.php\n"
  },
  {
    "path": "tests/codeception/backend/functional/LoginCept.php",
    "content": "<?php\n\nuse tests\\codeception\\backend\\FunctionalTester;\nuse tests\\codeception\\common\\_pages\\LoginPage;\n\n$I = new FunctionalTester($scenario);\n$I->wantTo('ensure login page works');\n\n$loginPage = LoginPage::openBy($I);\n\n$I->amGoingTo('submit login form with no data');\n$loginPage->login('', '');\n$I->expectTo('see validations errors');\n$I->see('Username cannot be blank.', '.help-block');\n$I->see('Password cannot be blank.', '.help-block');\n\n$I->amGoingTo('try to login with wrong credentials');\n$I->expectTo('see validations errors');\n$loginPage->login('admin', 'wrong');\n$I->expectTo('see validations errors');\n$I->see('Incorrect username or password.', '.help-block');\n\n$I->amGoingTo('try to login with correct credentials');\n$loginPage->login('erau', 'password_0');\n$I->expectTo('see that user is logged');\n$I->seeLink('Logout (erau)');\n$I->dontSeeLink('Login');\n$I->dontSeeLink('Signup');\n"
  },
  {
    "path": "tests/codeception/backend/functional/_bootstrap.php",
    "content": "<?php\nnew yii\\web\\Application(require(dirname(dirname(__DIR__)) . '/config/backend/functional.php'));\n"
  },
  {
    "path": "tests/codeception/backend/functional.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for functional (integration) tests.\n# emulate web requests and make application process them.\n# (tip: better to use with frameworks).\n\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n#basic/web/index.php\nclass_name: FunctionalTester\nmodules:\n    enabled:\n      - Filesystem\n      - Yii2\n      - tests\\codeception\\common\\_support\\FixtureHelper\n    config:\n        Yii2:\n            configFile: '../config/backend/functional.php'\n"
  },
  {
    "path": "tests/codeception/backend/unit/DbTestCase.php",
    "content": "<?php\n\nnamespace backend\\tests\\unit;\n\nclass DbTestCase extends \\yii\\codeception\\DbTestCase\n{\n    public $appConfig = '@tests/codeception/config/backend/unit.php';\n}\n"
  },
  {
    "path": "tests/codeception/backend/unit/TestCase.php",
    "content": "<?php\n\nnamespace backend\\tests\\unit;\n\nclass TestCase extends \\yii\\codeception\\TestCase\n{\n    public $appConfig = '@tests/codeception/config/backend/unit.php';\n}\n"
  },
  {
    "path": "tests/codeception/backend/unit/_bootstrap.php",
    "content": "<?php\n// Here you can initialize variables that will for your tests\n"
  },
  {
    "path": "tests/codeception/backend/unit/fixtures/data/.gitkeep",
    "content": ""
  },
  {
    "path": "tests/codeception/backend/unit.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for unit (internal) tests.\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n\nclass_name: UnitTester\n"
  },
  {
    "path": "tests/codeception/bin/_bootstrap.php",
    "content": "<?php\n/**\n * Yii console bootstrap file.\n *\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\n// fcgi doesn't have STDIN and STDOUT defined by default\ndefined('STDIN') or define('STDIN', fopen('php://stdin', 'r'));\ndefined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w'));\n\ndefined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(__DIR__))));\n\nrequire_once(YII_APP_BASE_PATH . '/vendor/autoload.php');\nrequire_once(YII_APP_BASE_PATH . '/vendor/yiisoft/yii2/Yii.php');\nrequire_once(YII_APP_BASE_PATH . '/common/config/bootstrap.php');\n\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n\nYii::setAlias('@tests', dirname(dirname(__DIR__)));\n"
  },
  {
    "path": "tests/codeception/bin/yii",
    "content": "#!/usr/bin/env php\n<?php\n/**\n * Yii console bootstrap file.\n *\n * @link http://www.yiiframework.com/\n * @copyright Copyright (c) 2008 Yii Software LLC\n * @license http://www.yiiframework.com/license/\n */\n\nrequire_once __DIR__ . '/_bootstrap.php';\n\n$config = yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/console/config/main.php'),\n    require(YII_APP_BASE_PATH . '/console/config/main-local.php'),\n    require(dirname(__DIR__) . '/config/config.php'),\n    [\n        'controllerMap' => [\n            'fixture' => [\n                'class' => 'yii\\faker\\FixtureController',\n                'fixtureDataPath' => '@tests/codeception/common/fixtures/data',\n                'templatePath' => '@tests/codeception/common/templates/fixtures',\n            ],\n        ],\n    ]\n);\n\n$application = new yii\\console\\Application($config);\n$exitCode = $application->run();\nexit($exitCode);\n"
  },
  {
    "path": "tests/codeception/bin/yii.bat",
    "content": "@echo off\n\nrem -------------------------------------------------------------\nrem  Yii command line bootstrap script for Windows.\nrem\nrem  @author Qiang Xue <qiang.xue@gmail.com>\nrem  @link http://www.yiiframework.com/\nrem  @copyright Copyright (c) 2008 Yii Software LLC\nrem  @license http://www.yiiframework.com/license/\nrem -------------------------------------------------------------\n\n@setlocal\n\nset YII_PATH=%~dp0\n\nif \"%PHP_COMMAND%\" == \"\" set PHP_COMMAND=php.exe\n\n\"%PHP_COMMAND%\" \"%YII_PATH%yii_acceptance\" %*\n\n@endlocal\n"
  },
  {
    "path": "tests/codeception/common/.gitignore",
    "content": "# these files are auto generated by codeception build\n/unit/UnitTester.php\n/functional/FunctionalTester.php\n/acceptance/AcceptanceTester.php\n"
  },
  {
    "path": "tests/codeception/common/_bootstrap.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n\ndefined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(__DIR__))));\n\nrequire_once(YII_APP_BASE_PATH . '/vendor/autoload.php');\nrequire_once(YII_APP_BASE_PATH . '/vendor/yiisoft/yii2/Yii.php');\nrequire_once(YII_APP_BASE_PATH . '/common/config/bootstrap.php');\n\n// set correct script paths\n$_SERVER['SERVER_NAME'] = 'localhost';\n\nYii::setAlias('@tests', dirname(dirname(__DIR__)));\n"
  },
  {
    "path": "tests/codeception/common/_output/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "tests/codeception/common/_pages/LoginPage.php",
    "content": "<?php\n\nnamespace tests\\codeception\\common\\_pages;\n\nuse yii\\codeception\\BasePage;\n\n/**\n * Represents loging page\n * @property \\codeception_frontend\\AcceptanceTester|\\codeception_frontend\\FunctionalTester|\\codeception_backend\\AcceptanceTester|\\codeception_backend\\FunctionalTester $actor\n */\nclass LoginPage extends BasePage\n{\n    public $route = 'site/login';\n\n    /**\n     * @param string $username\n     * @param string $password\n     */\n    public function login($username, $password)\n    {\n        $this->actor->fillField('input[name=\"LoginForm[username]\"]', $username);\n        $this->actor->fillField('input[name=\"LoginForm[password]\"]', $password);\n        $this->actor->click('login-button');\n    }\n}\n"
  },
  {
    "path": "tests/codeception/common/_support/FixtureHelper.php",
    "content": "<?php\n\nnamespace tests\\codeception\\common\\_support;\n\nuse tests\\codeception\\common\\fixtures\\UserFixture;\nuse Codeception\\Module;\nuse yii\\test\\FixtureTrait;\n\n/**\n * This helper is used to populate database with needed fixtures before any tests should be run.\n * For example - populate database with demo login user that should be used in acceptance and functional tests.\n * All fixtures will be loaded before suite will be starded and unloaded after it.\n */\nclass FixtureHelper extends Module\n{\n\n    /**\n     * Redeclare visibility because codeception includes all public methods that not starts from \"_\"\n     * and not excluded by module settings, in actor class.\n     */\n    use FixtureTrait {\n        loadFixtures as protected;\n        fixtures as protected;\n        globalFixtures as protected;\n        unloadFixtures as protected;\n        getFixtures as protected;\n        getFixture as protected;\n    }\n\n    /**\n     * Method called before any suite tests run. Loads User fixture login user\n     * to use in acceptance and functional tests.\n     * @param array $settings\n     */\n    public function _beforeSuite($settings = [])\n    {\n        $this->loadFixtures();\n    }\n\n    /**\n     * Method is called after all suite tests run\n     */\n    public function _afterSuite()\n    {\n        $this->unloadFixtures();\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function fixtures()\n    {\n        return [\n            'user' => [\n                'class' => UserFixture::className(),\n                'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php',\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/codeception/common/codeception.yml",
    "content": "namespace: tests\\codeception\\common\nactor: Tester\npaths:\n    tests: .\n    log: _output\n    data: _data\n    helpers: _support\nsettings:\n    bootstrap: _bootstrap.php\n    suite_class: \\PHPUnit_Framework_TestSuite\n    colors: true\n    memory_limit: 1024M\n    log: true\n"
  },
  {
    "path": "tests/codeception/common/fixtures/UserFixture.php",
    "content": "<?php\n\nnamespace tests\\codeception\\common\\fixtures;\n\nuse yii\\test\\ActiveFixture;\n\n/**\n * User fixture\n */\nclass UserFixture extends ActiveFixture\n{\n    public $modelClass = 'common\\models\\User';\n}\n"
  },
  {
    "path": "tests/codeception/common/fixtures/data/init_login.php",
    "content": "<?php\n\nreturn [\n    [\n        'username' => 'erau',\n        'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI',\n        // password_0\n        'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne',\n        'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490',\n        'created_at' => '1392559490',\n        'updated_at' => '1392559490',\n        'email' => 'sfriesen@jenkins.info',\n    ],\n];\n"
  },
  {
    "path": "tests/codeception/common/templates/fixtures/user.php",
    "content": "<?php\n/**\n * @var $faker \\Faker\\Generator\n * @var $index integer\n */\n\n$security = Yii::$app->getSecurity();\n\nreturn [\n    'username' => $faker->userName,\n    'email' => $faker->email,\n    'auth_key' => $security->generateRandomString(),\n    'password_hash' => $security->generatePasswordHash('password_' . $index),\n    'password_reset_token' => $security->generateRandomString() . '_' . time(),\n    'created_at' => time(),\n    'updated_at' => time(),\n];\n"
  },
  {
    "path": "tests/codeception/common/unit/DbTestCase.php",
    "content": "<?php\n\nnamespace tests\\codeception\\common\\unit;\n\n/**\n * @inheritdoc\n */\nclass DbTestCase extends \\yii\\codeception\\DbTestCase\n{\n    public $appConfig = '@tests/codeception/config/common/unit.php';\n}\n"
  },
  {
    "path": "tests/codeception/common/unit/TestCase.php",
    "content": "<?php\n\nnamespace tests\\codeception\\common\\unit;\n\n/**\n * @inheritdoc\n */\nclass TestCase extends \\yii\\codeception\\TestCase\n{\n    public $appConfig = '@tests/codeception/config/common/unit.php';\n}\n"
  },
  {
    "path": "tests/codeception/common/unit/_bootstrap.php",
    "content": "<?php\n// Here you can initialize variables that will for your tests\n"
  },
  {
    "path": "tests/codeception/common/unit/fixtures/data/models/user.php",
    "content": "<?php\n\nreturn [\n    [\n        'username' => 'bayer.hudson',\n        'auth_key' => 'HP187Mvq7Mmm3CTU80dLkGmni_FUH_lR',\n        //password_0\n        'password_hash' => '$2y$13$EjaPFBnZOQsHdGuHI.xvhuDp1fHpo8hKRSk6yshqa9c5EG8s3C3lO',\n        'password_reset_token' => 'ExzkCOaYc1L8IOBs4wdTGGbgNiG3Wz1I_1402312317',\n        'created_at' => '1402312317',\n        'updated_at' => '1402312317',\n        'email' => 'nicole.paucek@schultz.info',\n    ],\n];\n"
  },
  {
    "path": "tests/codeception/common/unit/models/LoginFormTest.php",
    "content": "<?php\n\nnamespace tests\\codeception\\common\\unit\\models;\n\nuse Yii;\nuse tests\\codeception\\common\\unit\\DbTestCase;\nuse Codeception\\Specify;\nuse common\\models\\LoginForm;\nuse tests\\codeception\\common\\fixtures\\UserFixture;\n\n/**\n * Login form test\n */\nclass LoginFormTest extends DbTestCase\n{\n\n    use Specify;\n\n    public function setUp()\n    {\n        parent::setUp();\n\n        Yii::configure(Yii::$app, [\n            'components' => [\n                'user' => [\n                    'class' => 'yii\\web\\User',\n                    'identityClass' => 'common\\models\\User',\n                ],\n            ],\n        ]);\n    }\n\n    protected function tearDown()\n    {\n        Yii::$app->user->logout();\n        parent::tearDown();\n    }\n\n    public function testLoginNoUser()\n    {\n        $model = new LoginForm([\n            'username' => 'not_existing_username',\n            'password' => 'not_existing_password',\n        ]);\n\n        $this->specify('user should not be able to login, when there is no identity', function () use ($model) {\n            expect('model should not login user', $model->login())->false();\n            expect('user should not be logged in', Yii::$app->user->isGuest)->true();\n        });\n    }\n\n    public function testLoginWrongPassword()\n    {\n        $model = new LoginForm([\n            'username' => 'bayer.hudson',\n            'password' => 'wrong_password',\n        ]);\n\n        $this->specify('user should not be able to login with wrong password', function () use ($model) {\n            expect('model should not login user', $model->login())->false();\n            expect('error message should be set', $model->errors)->hasKey('password');\n            expect('user should not be logged in', Yii::$app->user->isGuest)->true();\n        });\n    }\n\n    public function testLoginCorrect()\n    {\n\n        $model = new LoginForm([\n            'username' => 'bayer.hudson',\n            'password' => 'password_0',\n        ]);\n\n        $this->specify('user should be able to login with correct credentials', function () use ($model) {\n            expect('model should login user', $model->login())->true();\n            expect('error message should not be set', $model->errors)->hasntKey('password');\n            expect('user should be logged in', Yii::$app->user->isGuest)->false();\n        });\n    }\n\n    /**\n     * @inheritdoc\n     */\n    public function fixtures()\n    {\n        return [\n            'user' => [\n                'class' => UserFixture::className(),\n                'dataFile' => '@tests/codeception/common/unit/fixtures/data/models/user.php'\n            ],\n        ];\n    }\n\n}\n"
  },
  {
    "path": "tests/codeception/common/unit.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for unit (internal) tests.\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n\nclass_name: UnitTester\n"
  },
  {
    "path": "tests/codeception/config/acceptance.php",
    "content": "<?php\n/**\n * Application configuration shared by all applications acceptance tests\n */\nreturn [\n\n];"
  },
  {
    "path": "tests/codeception/config/backend/acceptance.php",
    "content": "<?php\ndefined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(dirname(__DIR__)))));\n\n/**\n * Application configuration for backend acceptance tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/backend/config/main.php'),\n    require(YII_APP_BASE_PATH . '/backend/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/acceptance.php'),\n    require(__DIR__ . '/config.php'),\n    [\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/backend/config.php",
    "content": "<?php\n/**\n * Application configuration for all backend test types\n */\nreturn [];"
  },
  {
    "path": "tests/codeception/config/backend/functional.php",
    "content": "<?php\n$_SERVER['SCRIPT_FILENAME'] = YII_TEST_BACKEND_ENTRY_FILE;\n$_SERVER['SCRIPT_NAME'] = YII_BACKEND_TEST_ENTRY_URL;\n\n/**\n * Application configuration for backend functional tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/backend/config/main.php'),\n    require(YII_APP_BASE_PATH . '/backend/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/functional.php'),\n    require(__DIR__ . '/config.php'),\n    [\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/backend/unit.php",
    "content": "<?php\n\n/**\n * Application configuration for backend unit tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/backend/config/main.php'),\n    require(YII_APP_BASE_PATH . '/backend/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/unit.php'),\n    require(__DIR__ . '/config.php'),\n    [\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/common/unit.php",
    "content": "<?php\n/**\n * Application config for common unit tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/unit.php'),\n    [\n        'id' => 'app-common',\n        'basePath' => dirname(__DIR__),\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/config.php",
    "content": "<?php\n\n$MYSQL_PORT_3306_TCP_ADDR = env('MYSQL_PORT_3306_TCP_ADDR', 'localhost');\n$MYSQL_TESTS_DB_NAME = env('MYSQL_INSTANCE_NAME', 'yii2advanced_tests');\n$MYSQL_USERNAME = env('MYSQL_USERNAME', 'root');\n$MYSQL_PASSWORD = env('MYSQL_PASSWORD', '');\n\n/**\n * Application configuration shared by all applications and test types\n */\nreturn [\n    'components' => [\n        'db' => [\n            'class' => 'yii\\db\\Connection',\n            'dsn' => 'mysql:host='.$MYSQL_PORT_3306_TCP_ADDR.';dbname='.$MYSQL_TESTS_DB_NAME,\n            'username' => $MYSQL_USERNAME,\n            'password' => $MYSQL_PASSWORD,\n            'charset' => 'utf8mb4',\n        ],\n        'mailer' => [\n            'useFileTransport' => true,\n        ],\n        'urlManager' => [\n            'showScriptName' => true,\n        ],\n    ],\n];\n"
  },
  {
    "path": "tests/codeception/config/console/unit.php",
    "content": "<?php\n/**\n * Application configuration for console unit tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/console/config/main.php'),\n    require(YII_APP_BASE_PATH . '/console/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/unit.php'),\n    [\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/frontend/acceptance.php",
    "content": "<?php\ndefined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(dirname(__DIR__)))));\n\n/**\n * Application configuration for frontend acceptance tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/frontend/config/main.php'),\n    require(YII_APP_BASE_PATH . '/frontend/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/acceptance.php'),\n    require(__DIR__ . '/config.php'),\n    [\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/frontend/config.php",
    "content": "<?php\n/**\n * Application configuration for all frontend test types\n */\nreturn [];"
  },
  {
    "path": "tests/codeception/config/frontend/functional.php",
    "content": "<?php\n$_SERVER['SCRIPT_FILENAME'] = FRONTEND_ENTRY_FILE;\n$_SERVER['SCRIPT_NAME'] = FRONTEND_ENTRY_URL;\n\n/**\n * Application configuration for frontend functional tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/frontend/config/main.php'),\n    require(YII_APP_BASE_PATH . '/frontend/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/functional.php'),\n    require(__DIR__ . '/config.php'),\n    [\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/frontend/unit.php",
    "content": "<?php\n\n/**\n * Application configuration for frontend unit tests\n */\nreturn yii\\helpers\\ArrayHelper::merge(\n    require(YII_APP_BASE_PATH . '/common/config/main.php'),\n    require(YII_APP_BASE_PATH . '/common/config/main-local.php'),\n    require(YII_APP_BASE_PATH . '/frontend/config/main.php'),\n    require(YII_APP_BASE_PATH . '/frontend/config/main-local.php'),\n    require(dirname(__DIR__) . '/config.php'),\n    require(dirname(__DIR__) . '/unit.php'),\n    require(__DIR__ . '/config.php'),\n    [\n    ]\n);\n"
  },
  {
    "path": "tests/codeception/config/functional.php",
    "content": "<?php\n/**\n * Application configuration shared by all applications functional tests\n */\nreturn [\n\n];"
  },
  {
    "path": "tests/codeception/config/unit.php",
    "content": "<?php\n/**\n * Application configuration shared by all applications unit tests\n */\nreturn [\n\n];"
  },
  {
    "path": "tests/codeception/console/.gitignore",
    "content": "# these files are auto generated by codeception build\n/unit/UnitTester.php\n"
  },
  {
    "path": "tests/codeception/console/_bootstrap.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n\ndefined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(__DIR__))));\n\nrequire_once(YII_APP_BASE_PATH . '/vendor/autoload.php');\nrequire_once(YII_APP_BASE_PATH . '/vendor/yiisoft/yii2/Yii.php');\nrequire_once(YII_APP_BASE_PATH . '/common/config/bootstrap.php');\nrequire_once(YII_APP_BASE_PATH . '/console/config/bootstrap.php');\n\n// set correct script paths\n$_SERVER['SERVER_NAME'] = 'localhost';\n\nYii::setAlias('@tests', dirname(dirname(__DIR__)));\n"
  },
  {
    "path": "tests/codeception/console/_output/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "tests/codeception/console/codeception.yml",
    "content": "namespace: tests\\codeception\\console\nactor: Tester\npaths:\n    tests: .\n    log: _output\n    data: _data\n    helpers: _support\nsettings:\n    bootstrap: _bootstrap.php\n    suite_class: \\PHPUnit_Framework_TestSuite\n    colors: true\n    memory_limit: 1024M\n    log: true\n"
  },
  {
    "path": "tests/codeception/console/unit/DbTestCase.php",
    "content": "<?php\n\nnamespace tests\\codeception\\console\\unit;\n\n/**\n * @inheritdoc\n */\nclass DbTestCase extends \\yii\\codeception\\DbTestCase\n{\n    public $appConfig = '@tests/codeception/config/console/config.php';\n}\n"
  },
  {
    "path": "tests/codeception/console/unit/TestCase.php",
    "content": "<?php\n\nnamespace tests\\codeception\\console\\unit;\n\n/**\n * @inheritdoc\n */\nclass TestCase extends \\yii\\codeception\\TestCase\n{\n    public $appConfig = '@tests/codeception/config/console/config.php';\n}\n"
  },
  {
    "path": "tests/codeception/console/unit/_bootstrap.php",
    "content": "<?php\n// Here you can initialize variables that will for your tests\n"
  },
  {
    "path": "tests/codeception/console/unit/fixtures/data/.gitkeep",
    "content": ""
  },
  {
    "path": "tests/codeception/console/unit.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for unit (internal) tests.\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n\nclass_name: UnitTester\n"
  },
  {
    "path": "tests/codeception/frontend/.gitignore",
    "content": "# these files are auto generated by codeception build\n/unit/UnitTester.php\n/functional/FunctionalTester.php\n/acceptance/AcceptanceTester.php\n"
  },
  {
    "path": "tests/codeception/frontend/_bootstrap.php",
    "content": "<?php\ndefined('YII_DEBUG') or define('YII_DEBUG', true);\ndefined('YII_ENV') or define('YII_ENV', 'test');\n\ndefined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', dirname(dirname(dirname(__DIR__))));\n\ndefined('FRONTEND_ENTRY_URL') or define('FRONTEND_ENTRY_URL', \\Codeception\\Configuration::config()['config']['test_entry_url']);\ndefined('FRONTEND_ENTRY_FILE') or define('FRONTEND_ENTRY_FILE', YII_APP_BASE_PATH . '/frontend/web/index-test.php');\n\nrequire_once(YII_APP_BASE_PATH . '/vendor/autoload.php');\nrequire_once(YII_APP_BASE_PATH . '/vendor/yiisoft/yii2/Yii.php');\nrequire_once(YII_APP_BASE_PATH . '/common/config/bootstrap.php');\nrequire_once(YII_APP_BASE_PATH . '/frontend/config/bootstrap.php');\n\n// set correct script paths\n\n// the entry script file path for functional and acceptance tests\n$_SERVER['SCRIPT_FILENAME'] = FRONTEND_ENTRY_FILE;\n$_SERVER['SCRIPT_NAME'] = FRONTEND_ENTRY_URL;\n$_SERVER['SERVER_NAME'] = 'localhost';\n\nYii::setAlias('@tests', dirname(dirname(__DIR__)));\n"
  },
  {
    "path": "tests/codeception/frontend/_output/.gitignore",
    "content": "*\n!.gitignore\n"
  },
  {
    "path": "tests/codeception/frontend/_pages/AboutPage.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\_pages;\n\nuse yii\\codeception\\BasePage;\n\n/**\n * Represents about page\n * @property \\codeception_frontend\\AcceptanceTester|\\codeception_frontend\\FunctionalTester $actor\n */\nclass AboutPage extends BasePage\n{\n    public $route = 'site/about';\n}\n"
  },
  {
    "path": "tests/codeception/frontend/_pages/ContactPage.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\_pages;\n\nuse yii\\codeception\\BasePage;\n\n/**\n * Represents contact page\n * @property \\codeception_frontend\\AcceptanceTester|\\codeception_frontend\\FunctionalTester $actor\n */\nclass ContactPage extends BasePage\n{\n    public $route = 'site/contact';\n\n    /**\n     * @param array $contactData\n     */\n    public function submit(array $contactData)\n    {\n        foreach ($contactData as $field => $value) {\n            $inputType = $field === 'body' ? 'textarea' : 'input';\n            $this->actor->fillField($inputType . '[name=\"ContactForm[' . $field . ']\"]', $value);\n        }\n        $this->actor->click('contact-button');\n    }\n}\n"
  },
  {
    "path": "tests/codeception/frontend/_pages/SignupPage.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\_pages;\n\nuse \\yii\\codeception\\BasePage;\n\n/**\n * Represents signup page\n * @property \\codeception_frontend\\AcceptanceTester|\\codeception_frontend\\FunctionalTester $actor\n */\nclass SignupPage extends BasePage\n{\n\n    public $route = 'site/signup';\n\n    /**\n     * @param array $signupData\n     */\n    public function submit(array $signupData)\n    {\n        foreach ($signupData as $field => $value) {\n            $inputType = $field === 'body' ? 'textarea' : 'input';\n            $this->actor->fillField($inputType . '[name=\"SignupForm[' . $field . ']\"]', $value);\n        }\n        $this->actor->click('signup-button');\n    }\n}\n"
  },
  {
    "path": "tests/codeception/frontend/acceptance/AboutCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\AcceptanceTester;\nuse tests\\codeception\\frontend\\_pages\\AboutPage;\n\n$I = new AcceptanceTester($scenario);\n$I->wantTo('ensure that about works');\nAboutPage::openBy($I);\n$I->see('About', 'h1');\n"
  },
  {
    "path": "tests/codeception/frontend/acceptance/ContactCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\AcceptanceTester;\nuse tests\\codeception\\frontend\\_pages\\ContactPage;\n\n$I = new AcceptanceTester($scenario);\n$I->wantTo('ensure that contact works');\n\n$contactPage = ContactPage::openBy($I);\n\n$I->see('Contact', 'h1');\n\n$I->amGoingTo('submit contact form with no data');\n$contactPage->submit([]);\n$I->expectTo('see validations errors');\n$I->see('Contact', 'h1');\n$I->see('Name cannot be blank', '.help-block');\n$I->see('Email cannot be blank', '.help-block');\n$I->see('Subject cannot be blank', '.help-block');\n$I->see('Body cannot be blank', '.help-block');\n$I->see('The verification code is incorrect', '.help-block');\n\n$I->amGoingTo('submit contact form with not correct email');\n$contactPage->submit([\n    'name' => 'tester',\n    'email' => 'tester.email',\n    'subject' => 'test subject',\n    'body' => 'test content',\n    'verifyCode' => 'testme',\n]);\n$I->expectTo('see that email adress is wrong');\n$I->dontSee('Name cannot be blank', '.help-block');\n$I->see('Email is not a valid email address.', '.help-block');\n$I->dontSee('Subject cannot be blank', '.help-block');\n$I->dontSee('Body cannot be blank', '.help-block');\n$I->dontSee('The verification code is incorrect', '.help-block');\n\n$I->amGoingTo('submit contact form with correct data');\n$contactPage->submit([\n    'name' => 'tester',\n    'email' => 'tester@example.com',\n    'subject' => 'test subject',\n    'body' => 'test content',\n    'verifyCode' => 'testme',\n]);\n$I->see('Thank you for contacting us. We will respond to you as soon as possible.');\n"
  },
  {
    "path": "tests/codeception/frontend/acceptance/HomeCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\AcceptanceTester;\n\n$I = new AcceptanceTester($scenario);\n$I->wantTo('ensure that home page works');\n$I->amOnPage(Yii::$app->homeUrl);\n$I->see('My Company');\n$I->seeLink('About');\n$I->click('About');\n$I->see('This is the About page.');\n"
  },
  {
    "path": "tests/codeception/frontend/acceptance/LoginCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\AcceptanceTester;\nuse tests\\codeception\\common\\_pages\\LoginPage;\n\n$I = new AcceptanceTester($scenario);\n$I->wantTo('ensure login page works');\n\n$loginPage = LoginPage::openBy($I);\n\n$I->amGoingTo('submit login form with no data');\n$loginPage->login('', '');\n$I->expectTo('see validations errors');\n$I->see('Username cannot be blank.', '.help-block');\n$I->see('Password cannot be blank.', '.help-block');\n\n$I->amGoingTo('try to login with wrong credentials');\n$I->expectTo('see validations errors');\n$loginPage->login('admin', 'wrong');\n$I->expectTo('see validations errors');\n$I->see('Incorrect username or password.', '.help-block');\n\n$I->amGoingTo('try to login with correct credentials');\n$loginPage->login('erau', 'password_0');\n$I->expectTo('see that user is logged');\n$I->seeLink('Logout (erau)');\n$I->dontSeeLink('Login');\n$I->dontSeeLink('Signup');\n/** Uncomment if using WebDriver\n * $I->click('Logout (erau)');\n * $I->dontSeeLink('Logout (erau)');\n * $I->seeLink('Login');\n */\n"
  },
  {
    "path": "tests/codeception/frontend/acceptance/SignupCest.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\acceptance;\n\nuse tests\\codeception\\frontend\\_pages\\SignupPage;\nuse common\\models\\User;\n\nclass SignupCest\n{\n\n    /**\n     * This method is called before each cest class test method\n     * @param \\Codeception\\Event\\TestEvent $event\n     */\n    public function _before($event)\n    {\n    }\n\n    /**\n     * This method is called after each cest class test method, even if test failed.\n     * @param \\Codeception\\Event\\TestEvent $event\n     */\n    public function _after($event)\n    {\n        User::deleteAll([\n            'email' => 'tester.email@example.com',\n            'username' => 'tester',\n        ]);\n    }\n\n    /**\n     * This method is called when test fails.\n     * @param \\Codeception\\Event\\FailEvent $event\n     */\n    public function _fail($event)\n    {\n    }\n\n    /**\n     * @param \\codeception_frontend\\AcceptanceTester $I\n     * @param \\Codeception\\Scenario $scenario\n     */\n    public function testUserSignup($I, $scenario)\n    {\n        $I->wantTo('ensure that signup works');\n\n        $signupPage = SignupPage::openBy($I);\n        $I->see('Signup', 'h1');\n        $I->see('Please fill out the following fields to signup:');\n\n        $I->amGoingTo('submit signup form with no data');\n\n        $signupPage->submit([]);\n\n        $I->expectTo('see validation errors');\n        $I->see('Username cannot be blank.', '.help-block');\n        $I->see('Email cannot be blank.', '.help-block');\n        $I->see('Password cannot be blank.', '.help-block');\n\n        $I->amGoingTo('submit signup form with not correct email');\n        $signupPage->submit([\n            'username' => 'tester',\n            'email' => 'tester.email',\n            'password' => 'tester_password',\n        ]);\n\n        $I->expectTo('see that email address is wrong');\n        $I->dontSee('Username cannot be blank.', '.help-block');\n        $I->dontSee('Password cannot be blank.', '.help-block');\n        $I->see('Email is not a valid email address.', '.help-block');\n\n        $I->amGoingTo('submit signup form with correct email');\n        $signupPage->submit([\n            'username' => 'tester',\n            'email' => 'tester.email@example.com',\n            'password' => 'tester_password',\n        ]);\n\n        $I->expectTo('see that user logged in');\n        $I->seeLink('Logout (tester)');\n    }\n}\n"
  },
  {
    "path": "tests/codeception/frontend/acceptance/_bootstrap.php",
    "content": "<?php\nnew yii\\web\\Application(require(dirname(dirname(__DIR__)) . '/config/frontend/acceptance.php'));\n"
  },
  {
    "path": "tests/codeception/frontend/acceptance.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for acceptance tests.\n# perform tests in browser using the Selenium-like tools.\n# powered by Mink (http://mink.behat.org).\n# (tip: that's what your customer will see).\n# (tip: test your ajax and javascript by one of Mink drivers).\n\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n\nclass_name: AcceptanceTester\nmodules:\n    enabled:\n        - PhpBrowser\n        - tests\\codeception\\common\\_support\\FixtureHelper\n# you can use WebDriver instead of PhpBrowser to test javascript and ajax.\n# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium\n# \"restart\" option is used by the WebDriver to start each time per test-file new session and cookies,\n# it is useful if you want to login in your app in each test.\n#        - WebDriver\n    config:\n        PhpBrowser:\n            url: 'http://localhost:8080'\n#        WebDriver:\n#            url: 'http://localhost'\n#            browser: firefox\n#            restart: true\n"
  },
  {
    "path": "tests/codeception/frontend/codeception.yml",
    "content": "namespace: tests\\codeception\\frontend\nactor: Tester\npaths:\n    tests: .\n    log: _output\n    data: _data\n    helpers: _support\nsettings:\n    bootstrap: _bootstrap.php\n    suite_class: \\PHPUnit_Framework_TestSuite\n    colors: true\n    memory_limit: 1024M\n    log: true\nconfig:\n    # the entry script URL (without host info) for functional and acceptance tests\n    # PLEASE ADJUST IT TO THE ACTUAL ENTRY SCRIPT URL\n    test_entry_url: /frontend/web/index-test.php\n"
  },
  {
    "path": "tests/codeception/frontend/functional/AboutCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\FunctionalTester;\nuse tests\\codeception\\frontend\\_pages\\AboutPage;\n\n$I = new FunctionalTester($scenario);\n$I->wantTo('ensure that about works');\nAboutPage::openBy($I);\n$I->see('About', 'h1');\n"
  },
  {
    "path": "tests/codeception/frontend/functional/ContactCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\FunctionalTester;\nuse tests\\codeception\\frontend\\_pages\\ContactPage;\n\n$I = new FunctionalTester($scenario);\n$I->wantTo('ensure that contact works');\n\n$contactPage = ContactPage::openBy($I);\n\n$I->see('Contact', 'h1');\n\n$I->amGoingTo('submit contact form with no data');\n$contactPage->submit([]);\n$I->expectTo('see validations errors');\n$I->see('Contact', 'h1');\n$I->see('Name cannot be blank', '.help-block');\n$I->see('Email cannot be blank', '.help-block');\n$I->see('Subject cannot be blank', '.help-block');\n$I->see('Body cannot be blank', '.help-block');\n$I->see('The verification code is incorrect', '.help-block');\n\n$I->amGoingTo('submit contact form with not correct email');\n$contactPage->submit([\n    'name' => 'tester',\n    'email' => 'tester.email',\n    'subject' => 'test subject',\n    'body' => 'test content',\n    'verifyCode' => 'testme',\n]);\n$I->expectTo('see that email adress is wrong');\n$I->dontSee('Name cannot be blank', '.help-block');\n$I->see('Email is not a valid email address.', '.help-block');\n$I->dontSee('Subject cannot be blank', '.help-block');\n$I->dontSee('Body cannot be blank', '.help-block');\n$I->dontSee('The verification code is incorrect', '.help-block');\n\n$I->amGoingTo('submit contact form with correct data');\n$contactPage->submit([\n    'name' => 'tester',\n    'email' => 'tester@example.com',\n    'subject' => 'test subject',\n    'body' => 'test content',\n    'verifyCode' => 'testme',\n]);\n$I->see('Thank you for contacting us. We will respond to you as soon as possible.');\n"
  },
  {
    "path": "tests/codeception/frontend/functional/HomeCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\FunctionalTester;\n$I = new FunctionalTester($scenario);\n$I->wantTo('ensure that home page works');\n$I->amOnPage(Yii::$app->homeUrl);\n$I->see('My Company');\n$I->seeLink('About');\n$I->click('About');\n$I->see('This is the About page.');\n"
  },
  {
    "path": "tests/codeception/frontend/functional/LoginCept.php",
    "content": "<?php\nuse tests\\codeception\\frontend\\FunctionalTester;\nuse tests\\codeception\\common\\_pages\\LoginPage;\n\n$I = new FunctionalTester($scenario);\n$I->wantTo('ensure login page works');\n\n$loginPage = LoginPage::openBy($I);\n\n$I->amGoingTo('submit login form with no data');\n$loginPage->login('', '');\n$I->expectTo('see validations errors');\n$I->see('Username cannot be blank.', '.help-block');\n$I->see('Password cannot be blank.', '.help-block');\n\n$I->amGoingTo('try to login with wrong credentials');\n$I->expectTo('see validations errors');\n$loginPage->login('admin', 'wrong');\n$I->expectTo('see validations errors');\n$I->see('Incorrect username or password.', '.help-block');\n\n$I->amGoingTo('try to login with correct credentials');\n$loginPage->login('erau', 'password_0');\n$I->expectTo('see that user is logged');\n$I->seeLink('Logout (erau)');\n$I->dontSeeLink('Login');\n$I->dontSeeLink('Signup');\n"
  },
  {
    "path": "tests/codeception/frontend/functional/SignupCest.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\functional;\n\nuse tests\\codeception\\frontend\\_pages\\SignupPage;\nuse common\\models\\User;\n\nclass SignupCest\n{\n\n    /**\n     * This method is called before each cest class test method\n     * @param \\Codeception\\Event\\TestEvent $event\n     */\n    public function _before($event)\n    {\n    }\n\n    /**\n     * This method is called after each cest class test method, even if test failed.\n     * @param \\Codeception\\Event\\TestEvent $event\n     */\n    public function _after($event)\n    {\n        User::deleteAll([\n            'email' => 'tester.email@example.com',\n            'username' => 'tester',\n        ]);\n    }\n\n    /**\n     * This method is called when test fails.\n     * @param \\Codeception\\Event\\FailEvent $event\n     */\n    public function _fail($event)\n    {\n\n    }\n\n    /**\n     *\n     * @param \\codeception_frontend\\FunctionalTester $I\n     * @param \\Codeception\\Scenario $scenario\n     */\n    public function testUserSignup($I, $scenario)\n    {\n        $I->wantTo('ensure that signup works');\n\n        $signupPage = SignupPage::openBy($I);\n        $I->see('Signup', 'h1');\n        $I->see('Please fill out the following fields to signup:');\n\n        $I->amGoingTo('submit signup form with no data');\n\n        $signupPage->submit([]);\n\n        $I->expectTo('see validation errors');\n        $I->see('Username cannot be blank.', '.help-block');\n        $I->see('Email cannot be blank.', '.help-block');\n        $I->see('Password cannot be blank.', '.help-block');\n\n        $I->amGoingTo('submit signup form with not correct email');\n        $signupPage->submit([\n            'username' => 'tester',\n            'email' => 'tester.email',\n            'password' => 'tester_password',\n        ]);\n\n        $I->expectTo('see that email address is wrong');\n        $I->dontSee('Username cannot be blank.', '.help-block');\n        $I->dontSee('Password cannot be blank.', '.help-block');\n        $I->see('Email is not a valid email address.', '.help-block');\n\n        $I->amGoingTo('submit signup form with correct email');\n        $signupPage->submit([\n            'username' => 'tester',\n            'email' => 'tester.email@example.com',\n            'password' => 'tester_password',\n        ]);\n\n        $I->expectTo('see that user is created');\n        $I->seeRecord('common\\models\\User', [\n            'username' => 'tester',\n            'email' => 'tester.email@example.com',\n        ]);\n\n        $I->expectTo('see that user logged in');\n        $I->seeLink('Logout (tester)');\n    }\n}\n"
  },
  {
    "path": "tests/codeception/frontend/functional/_bootstrap.php",
    "content": "<?php\n\nnew yii\\web\\Application(require(dirname(dirname(__DIR__)) . '/config/frontend/functional.php'));\n"
  },
  {
    "path": "tests/codeception/frontend/functional.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for functional (integration) tests.\n# emulate web requests and make application process them.\n# (tip: better to use with frameworks).\n\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n#basic/web/index.php\nclass_name: FunctionalTester\nmodules:\n    enabled:\n      - Filesystem\n      - Yii2\n      - tests\\codeception\\common\\_support\\FixtureHelper\n    config:\n        Yii2:\n            configFile: '../config/frontend/functional.php'\n"
  },
  {
    "path": "tests/codeception/frontend/unit/DbTestCase.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\unit;\n\n/**\n * @inheritdoc\n */\nclass DbTestCase extends \\yii\\codeception\\DbTestCase\n{\n    public $appConfig = '@tests/codeception/config/frontend/unit.php';\n}\n"
  },
  {
    "path": "tests/codeception/frontend/unit/TestCase.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\unit;\n\n/**\n * @inheritdoc\n */\nclass TestCase extends \\yii\\codeception\\TestCase\n{\n    public $appConfig = '@tests/codeception/config/frontend/unit.php';\n}\n"
  },
  {
    "path": "tests/codeception/frontend/unit/_bootstrap.php",
    "content": "<?php\n// Here you can initialize variables that will for your tests\n"
  },
  {
    "path": "tests/codeception/frontend/unit/fixtures/data/models/user.php",
    "content": "<?php\n\nreturn [\n    [\n        'username' => 'okirlin',\n        'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv',\n        'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi',\n        'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_' . time(),\n        'created_at' => '1391885313',\n        'updated_at' => '1391885313',\n        'email' => 'brady.renner@rutherford.com',\n    ],\n    [\n        'username' => 'troy.becker',\n        'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp',\n        'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2',\n        'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_' . time(),\n        'created_at' => '1391885313',\n        'updated_at' => '1391885313',\n        'email' => 'nicolas.dianna@hotmail.com',\n        'status' => '0',\n    ],\n];\n"
  },
  {
    "path": "tests/codeception/frontend/unit/models/ContactFormTest.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\unit\\models;\n\nuse Yii;\nuse tests\\codeception\\frontend\\unit\\TestCase;\nuse frontend\\models\\ContactForm;\n\nclass ContactFormTest extends TestCase\n{\n\n    use \\Codeception\\Specify;\n\n    protected function setUp()\n    {\n        parent::setUp();\n        Yii::$app->mailer->fileTransportCallback = function ($mailer, $message) {\n            return 'testing_message.eml';\n        };\n    }\n\n    protected function tearDown()\n    {\n        unlink($this->getMessageFile());\n        parent::tearDown();\n    }\n\n    public function testContact()\n    {\n        $model = new ContactForm();\n\n        $model->attributes = [\n            'name' => 'Tester',\n            'email' => 'tester@example.com',\n            'subject' => 'very important letter subject',\n            'body' => 'body of current message',\n        ];\n\n        $model->sendEmail('admin@example.com');\n\n        $this->specify('email should be send', function () {\n            expect('email file should exist', file_exists($this->getMessageFile()))->true();\n        });\n\n        $this->specify('message should contain correct data', function () use ($model) {\n            $emailMessage = file_get_contents($this->getMessageFile());\n\n            expect('email should contain user name', $emailMessage)->contains($model->name);\n            expect('email should contain sender email', $emailMessage)->contains($model->email);\n            expect('email should contain subject', $emailMessage)->contains($model->subject);\n            expect('email should contain body', $emailMessage)->contains($model->body);\n        });\n    }\n\n    private function getMessageFile()\n    {\n        return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';\n    }\n}\n"
  },
  {
    "path": "tests/codeception/frontend/unit/models/PasswordResetRequestFormTest.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\models;\n\nuse Yii;\nuse tests\\codeception\\frontend\\unit\\DbTestCase;\nuse frontend\\models\\PasswordResetRequestForm;\nuse tests\\codeception\\common\\fixtures\\UserFixture;\nuse common\\models\\User;\nuse Codeception\\Specify;\n\nclass PasswordResetRequestFormTest extends DbTestCase\n{\n    use Specify;\n\n    protected function setUp()\n    {\n        parent::setUp();\n\n        Yii::$app->mailer->fileTransportCallback = function ($mailer, $message) {\n            return 'testing_message.eml';\n        };\n    }\n\n    protected function tearDown()\n    {\n        @unlink($this->getMessageFile());\n\n        parent::tearDown();\n    }\n\n    public function testSendEmailWrongUser()\n    {\n        $this->specify('no user with such email, message should not be send', function () {\n\n            $model = new PasswordResetRequestForm();\n            $model->email = 'not-existing-email@example.com';\n\n            expect('email not send', $model->sendEmail())->false();\n\n        });\n\n        $this->specify('user is not active, message should not be send', function () {\n\n            $model = new PasswordResetRequestForm();\n            $model->email = $this->user[1]['email'];\n\n            expect('email not send', $model->sendEmail())->false();\n\n        });\n    }\n\n    public function testSendEmailCorrectUser()\n    {\n        $model = new PasswordResetRequestForm();\n        $model->email = $this->user[0]['email'];\n        $user = User::findOne(['password_reset_token' => $this->user[0]['password_reset_token']]);\n\n        expect('email sent', $model->sendEmail())->true();\n        expect('user has valid token', $user->password_reset_token)->notNull();\n\n        $this->specify('message has correct format', function () use ($model) {\n\n            expect('message file exists', file_exists($this->getMessageFile()))->true();\n\n            $message = file_get_contents($this->getMessageFile());\n            expect('message \"from\" is correct', $message)->contains(Yii::$app->params['supportEmail']);\n            expect('message \"to\" is correct', $message)->contains($model->email);\n\n        });\n    }\n\n    public function fixtures()\n    {\n        return [\n            'user' => [\n                'class' => UserFixture::className(),\n                'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'\n            ],\n        ];\n    }\n\n    private function getMessageFile()\n    {\n        return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';\n    }\n\n}\n"
  },
  {
    "path": "tests/codeception/frontend/unit/models/ResetPasswordFormTest.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\unit\\models;\n\nuse tests\\codeception\\frontend\\unit\\DbTestCase;\nuse tests\\codeception\\common\\fixtures\\UserFixture;\nuse frontend\\models\\ResetPasswordForm;\n\nclass ResetPasswordFormTest extends DbTestCase\n{\n\n    /**\n     * @expectedException \\yii\\base\\InvalidParamException\n     */\n    public function testResetWrongToken()\n    {\n        new ResetPasswordForm('notexistingtoken_1391882543');\n    }\n\n    /**\n     * @expectedException \\yii\\base\\InvalidParamException\n     */\n    public function testResetEmptyToken()\n    {\n        new ResetPasswordForm('');\n    }\n\n    public function testResetCorrectToken()\n    {\n        $form = new ResetPasswordForm($this->user[0]['password_reset_token']);\n        expect('password should be resetted', $form->resetPassword())->true();\n    }\n\n    public function fixtures()\n    {\n        return [\n            'user' => [\n                'class' => UserFixture::className(),\n                'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'\n            ],\n        ];\n    }\n\n}\n"
  },
  {
    "path": "tests/codeception/frontend/unit/models/SignupFormTest.php",
    "content": "<?php\n\nnamespace tests\\codeception\\frontend\\unit\\models;\n\nuse tests\\codeception\\frontend\\unit\\DbTestCase;\nuse tests\\codeception\\common\\fixtures\\UserFixture;\nuse Codeception\\Specify;\nuse frontend\\models\\SignupForm;\n\nclass SignupFormTest extends DbTestCase\n{\n\n    use Specify;\n\n    public function testCorrectSignup()\n    {\n        $model = new SignupForm([\n            'username' => 'some_username',\n            'email' => 'some_email@example.com',\n            'password' => 'some_password',\n        ]);\n\n        $user = $model->signup();\n\n        $this->assertInstanceOf('common\\models\\User', $user, 'user should be valid');\n\n        expect('username should be correct', $user->username)->equals('some_username');\n        expect('email should be correct', $user->email)->equals('some_email@example.com');\n        expect('password should be correct', $user->validatePassword('some_password'))->true();\n    }\n\n    public function testNotCorrectSignup()\n    {\n        $model = new SignupForm([\n            'username' => 'troy.becker',\n            'email' => 'nicolas.dianna@hotmail.com',\n            'password' => 'some_password',\n        ]);\n\n        expect('username and email are in use, user should not be created', $model->signup())->null();\n    }\n\n    public function fixtures()\n    {\n        return [\n            'user' => [\n                'class' => UserFixture::className(),\n                'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php',\n            ],\n        ];\n    }\n\n}\n"
  },
  {
    "path": "tests/codeception/frontend/unit.suite.yml",
    "content": "# Codeception Test Suite Configuration\n\n# suite for unit (internal) tests.\n# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.\n\nclass_name: UnitTester\n"
  },
  {
    "path": "tests/codeception.yml",
    "content": "include:\n  - codeception/common\n  - codeception/console\n  - codeception/backend\n  - codeception/frontend\n\npaths:\n  log: codeception/_output\n\nsettings:\n  colors: true\n"
  },
  {
    "path": "yii.bat",
    "content": "@echo off\n\nrem -------------------------------------------------------------\nrem  Yii command line bootstrap script for Windows.\nrem\nrem  @author Qiang Xue <qiang.xue@gmail.com>\nrem  @link http://www.yiiframework.com/\nrem  @copyright Copyright (c) 2008 Yii Software LLC\nrem  @license http://www.yiiframework.com/license/\nrem -------------------------------------------------------------\n\n@setlocal\n\nset YII_PATH=%~dp0\n\nif \"%PHP_COMMAND%\" == \"\" set PHP_COMMAND=php.exe\n\n\"%PHP_COMMAND%\" \"%YII_PATH%yii\" %*\n\n@endlocal\n"
  }
]