diff --git a/.bowerrc b/.bowerrc
new file mode 100644
index 0000000..1669168
--- /dev/null
+++ b/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory" : "vendor/bower"
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5d27534
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+/uploads
\ No newline at end of file
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 0000000..29c3bec
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,18 @@
+Mod_Autoindex
+
+ # Запрещаем просмотр содержимого папок
+ Options -Indexes
+
+
+Mod_Rewrite
+
+ Options +FollowSymlinks
+ # Включаем mod_rewrite
+ RewriteEngine On
+ IndexIgnore */*
+ # Перенаправляем administrator на входной скрипт админки
+ RewriteRule ^administrator/(.*)?$ /backend/web/$1 [L,PT]
+ RewriteRule ^storage/(.*)?$ /storage/$1 [L,PT]
+ # Перенаправляем все запросы на входной скрипт
+ RewriteRule ^([^/].*)?$ /frontend/web/$1
+
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 0000000..e98f03d
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,32 @@
+The Yii framework is free software. It is released under the terms of
+the following BSD License.
+
+Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Yii Software LLC nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..45e56ad
--- /dev/null
+++ b/README.md
@@ -0,0 +1,54 @@
+Yii 2 Advanced Project Template
+===============================
+
+Yii 2 Advanced Project Template is a skeleton [Yii 2](http://www.yiiframework.com/) application best for
+developing complex Web applications with multiple tiers.
+
+The template includes three tiers: front end, back end, and console, each of which
+is a separate Yii application.
+
+The template is designed to work in a team development environment. It supports
+deploying the application in different environments.
+
+Documentation is at [docs/guide/README.md](docs/guide/README.md).
+
+[](https://packagist.org/packages/yiisoft/yii2-app-advanced)
+[](https://packagist.org/packages/yiisoft/yii2-app-advanced)
+[](https://travis-ci.org/yiisoft/yii2-app-advanced)
+
+DIRECTORY STRUCTURE
+-------------------
+
+```
+common
+ config/ contains shared configurations
+ mail/ contains view files for e-mails
+ models/ contains model classes used in both backend and frontend
+console
+ config/ contains console configurations
+ controllers/ contains console controllers (commands)
+ migrations/ contains database migrations
+ models/ contains console-specific model classes
+ runtime/ contains files generated during runtime
+backend
+ assets/ contains application assets such as JavaScript and CSS
+ config/ contains backend configurations
+ controllers/ contains Web controller classes
+ models/ contains backend-specific model classes
+ runtime/ contains files generated during runtime
+ views/ contains view files for the Web application
+ web/ contains the entry script and Web resources
+frontend
+ assets/ contains application assets such as JavaScript and CSS
+ config/ contains frontend configurations
+ controllers/ contains Web controller classes
+ models/ contains frontend-specific model classes
+ runtime/ contains files generated during runtime
+ views/ contains view files for the Web application
+ web/ contains the entry script and Web resources
+ widgets/ contains frontend widgets
+vendor/ contains dependent 3rd-party packages
+environments/ contains environment-based overrides
+tests contains various tests for the advanced application
+ codeception/ contains tests developed with Codeception PHP Testing Framework
+```
diff --git a/backend/assets/AppAsset.php b/backend/assets/AppAsset.php
new file mode 100644
index 0000000..c262142
--- /dev/null
+++ b/backend/assets/AppAsset.php
@@ -0,0 +1,29 @@
+
+ * @since 2.0
+ */
+class AppAsset extends AssetBundle
+{
+ public $basePath = '@webroot';
+ public $baseUrl = '@web';
+ public $css = [
+ 'css/site.css',
+ ];
+ public $js = [
+ ];
+ public $depends = [
+ 'yii\web\YiiAsset',
+ 'yii\bootstrap\BootstrapAsset',
+ ];
+}
diff --git a/backend/config/.gitignore b/backend/config/.gitignore
new file mode 100644
index 0000000..20da318
--- /dev/null
+++ b/backend/config/.gitignore
@@ -0,0 +1,2 @@
+main-local.php
+params-local.php
\ No newline at end of file
diff --git a/backend/config/bootstrap.php b/backend/config/bootstrap.php
new file mode 100644
index 0000000..b3d9bbc
--- /dev/null
+++ b/backend/config/bootstrap.php
@@ -0,0 +1 @@
+ 'app-backend',
+ 'basePath' => dirname(__DIR__),
+ 'controllerNamespace' => 'backend\controllers',
+ 'bootstrap' => ['log'],
+ 'modules' => [],
+ 'components' => [
+ 'user' => [
+ 'identityClass' => 'common\models\User',
+ 'enableAutoLogin' => true,
+ ],
+ 'log' => [
+ 'traceLevel' => YII_DEBUG ? 3 : 0,
+ 'targets' => [
+ [
+ 'class' => 'yii\log\FileTarget',
+ 'levels' => ['error', 'warning'],
+ ],
+ ],
+ ],
+ 'errorHandler' => [
+ 'errorAction' => 'site/error',
+ ],
+ ],
+ 'params' => $params,
+];
diff --git a/backend/config/params.php b/backend/config/params.php
new file mode 100644
index 0000000..7f754b9
--- /dev/null
+++ b/backend/config/params.php
@@ -0,0 +1,4 @@
+ 'admin@example.com',
+];
diff --git a/backend/controllers/ParserController.php b/backend/controllers/ParserController.php
new file mode 100644
index 0000000..6637d68
--- /dev/null
+++ b/backend/controllers/ParserController.php
@@ -0,0 +1,70 @@
+ [
+ 'class' => AccessControl::className(),
+ 'rules' => [
+ [
+ 'actions' => ['index'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ],
+ ],
+ ],
+ 'verbs' => [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'logout' => ['post'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function actions()
+ {
+ return [
+ 'error' => [
+ 'class' => 'yii\web\ErrorAction',
+ ],
+ ];
+ }
+
+ public function actionIndex()
+ {
+ $model = new UploadForm();
+
+ if (Yii::$app->request->isPost) {
+ $model->file = UploadedFile::getInstance($model, 'file');
+
+ if ($model->file && $model->validate()) {
+ $model->file->saveAs(Yii::getAlias('@webroot') . '/uploads/' . $model->file->baseName . '.' . $model->file->extension);
+ }
+ }
+
+ return $this->render('parser', ['model' => $model]);
+ }
+
+
+
+}
diff --git a/backend/controllers/SiteController.php b/backend/controllers/SiteController.php
new file mode 100644
index 0000000..db3259a
--- /dev/null
+++ b/backend/controllers/SiteController.php
@@ -0,0 +1,83 @@
+ [
+ 'class' => AccessControl::className(),
+ 'rules' => [
+ [
+ 'actions' => ['login', 'error'],
+ 'allow' => true,
+ ],
+ [
+ 'actions' => ['logout', 'index'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ],
+ ],
+ ],
+ 'verbs' => [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'logout' => ['post'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function actions()
+ {
+ return [
+ 'error' => [
+ 'class' => 'yii\web\ErrorAction',
+ ],
+ ];
+ }
+
+ public function actionIndex()
+ {
+ return $this->render('index');
+ }
+
+ public function actionLogin()
+ {
+ if (!\Yii::$app->user->isGuest) {
+ return $this->goHome();
+ }
+
+ $model = new LoginForm();
+ if ($model->load(Yii::$app->request->post()) && $model->login()) {
+ return $this->goBack();
+ } else {
+ return $this->render('login', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ public function actionLogout()
+ {
+ Yii::$app->user->logout();
+
+ return $this->goHome();
+ }
+}
diff --git a/backend/models/.gitkeep b/backend/models/.gitkeep
new file mode 100644
index 0000000..72e8ffc
--- /dev/null
+++ b/backend/models/.gitkeep
@@ -0,0 +1 @@
+*
diff --git a/backend/models/UploadForm.php b/backend/models/UploadForm.php
new file mode 100644
index 0000000..35f91cf
--- /dev/null
+++ b/backend/models/UploadForm.php
@@ -0,0 +1,26 @@
+
+beginPage() ?>
+
+
+
+
+
+ = Html::csrfMetaTags() ?>
+ = Html::encode($this->title) ?>
+ head() ?>
+
+
+beginBody() ?>
+
+
+
+
+
+
+ = $content ?>
+
+
+ ['class' => 'nav nav-pills nav-stacked'],
+ 'items' => [
+ ['label' => 'Загрузка прайсов', 'url' => ['parser/index']],
+//
+ ],
+ ]);
+ ?>
+
+
+
+
+
+
+
+ endBody() ?>
+
+
+endPage() ?>
diff --git a/backend/views/parser/parser.php b/backend/views/parser/parser.php
new file mode 100644
index 0000000..fe48efd
--- /dev/null
+++ b/backend/views/parser/parser.php
@@ -0,0 +1,11 @@
+
+
+ ['enctype' => 'multipart/form-data']]) ?>
+
+= $form->field($model, 'file')->fileInput() ?>
+
+
Отправить
+
+
\ No newline at end of file
diff --git a/backend/views/site/error.php b/backend/views/site/error.php
new file mode 100644
index 0000000..0ba2574
--- /dev/null
+++ b/backend/views/site/error.php
@@ -0,0 +1,27 @@
+title = $name;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = nl2br(Html::encode($message)) ?>
+
+
+
+ The above error occurred while the Web server was processing your request.
+
+
+ Please contact us if you think this is a server error. Thank you.
+
+
+
diff --git a/backend/views/site/index.php b/backend/views/site/index.php
new file mode 100644
index 0000000..e6eb575
--- /dev/null
+++ b/backend/views/site/index.php
@@ -0,0 +1,16 @@
+title = 'Ital auto';
+?>
+
+
diff --git a/backend/views/site/login.php b/backend/views/site/login.php
new file mode 100644
index 0000000..ec9cc06
--- /dev/null
+++ b/backend/views/site/login.php
@@ -0,0 +1,35 @@
+title = 'Login';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out the following fields to login:
+
+
+
+ 'login-form']); ?>
+
+ = $form->field($model, 'username') ?>
+
+ = $form->field($model, 'password')->passwordInput() ?>
+
+ = $form->field($model, 'rememberMe')->checkbox() ?>
+
+
+ = Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
+
+
+
+
+
+
diff --git a/backend/web/.gitignore b/backend/web/.gitignore
new file mode 100644
index 0000000..3adbc3f
--- /dev/null
+++ b/backend/web/.gitignore
@@ -0,0 +1,3 @@
+/index.php
+/index-test.php
+uploads/
diff --git a/backend/web/.htaccess b/backend/web/.htaccess
new file mode 100644
index 0000000..fa96d7a
--- /dev/null
+++ b/backend/web/.htaccess
@@ -0,0 +1,8 @@
+RewriteEngine on
+
+RewriteBase /
+
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteCond %{REQUEST_FILENAME} !-f
+
+RewriteRule . index.php
\ No newline at end of file
diff --git a/backend/web/assets/.gitignore b/backend/web/assets/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/backend/web/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/backend/web/css/site.css b/backend/web/css/site.css
new file mode 100644
index 0000000..10988f6
--- /dev/null
+++ b/backend/web/css/site.css
@@ -0,0 +1,145 @@
+html,
+body {
+ height: 100%;
+}
+
+.wrap {
+ min-height: 100%;
+ height: auto;
+ margin: 0 auto -60px;
+ padding: 0 0 60px;
+}
+
+.wrap > .container {
+ padding: 70px 15px 20px;
+}
+
+.footer {
+ height: 60px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ padding-top: 20px;
+}
+
+.jumbotron {
+ text-align: center;
+ background-color: transparent;
+}
+
+.jumbotron .btn {
+ font-size: 21px;
+ padding: 14px 24px;
+}
+
+.not-set {
+ color: #c55;
+ font-style: italic;
+}
+
+/* add sorting icons to gridview sort links */
+a.asc:after, a.desc:after {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ padding-left: 5px;
+}
+
+a.asc:after {
+ content: /*"\e113"*/ "\e151";
+}
+
+a.desc:after {
+ content: /*"\e114"*/ "\e152";
+}
+
+.sort-numerical a.asc:after {
+ content: "\e153";
+}
+
+.sort-numerical a.desc:after {
+ content: "\e154";
+}
+
+.sort-ordinal a.asc:after {
+ content: "\e155";
+}
+
+.sort-ordinal a.desc:after {
+ content: "\e156";
+}
+
+.grid-view th {
+ white-space: nowrap;
+}
+
+.hint-block {
+ display: block;
+ margin-top: 5px;
+ color: #999;
+}
+
+.error-summary {
+ color: #a94442;
+ background: #fdf7f7;
+ border-left: 3px solid #eed3d7;
+ padding: 10px 20px;
+ margin: 0 0 15px 0;
+}
+
+.container{
+ min-width: 960px;
+}
+
+.left_block{
+ width: 15%;
+ float: left;
+}
+.right_block{
+ float: left;
+ width: 80%;
+ margin-left: 20px;
+}
+.active_{
+ background: none;
+}
+.non_active{
+ background: #adadad;
+}
+
+.site-login {
+ width: 700px;
+ margin: 100px auto;
+}
+
+.gallery_image{
+
+ position: relative;
+ margin-left: 20px;
+ margin-top: 20px;
+ display: inline-block;
+}
+.delete-gallery-item{
+ background-color: #fff;
+ opacity: 0.5;
+ font-size: 20px;
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ cursor: pointer;
+}
+
+.delete-field-item{
+ position: absolute;
+ top: 33%;
+ right: -35px;
+ font-size: 15px;
+ cursor: pointer;
+}
+
+.form-group{
+ position: relative;
+}
\ No newline at end of file
diff --git a/backend/web/favicon.ico b/backend/web/favicon.ico
new file mode 100644
index 0000000..580ed73
Binary files /dev/null and b/backend/web/favicon.ico differ
diff --git a/backend/web/robots.txt b/backend/web/robots.txt
new file mode 100644
index 0000000..1f53798
--- /dev/null
+++ b/backend/web/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /
diff --git a/common/config/.gitignore b/common/config/.gitignore
new file mode 100644
index 0000000..97c0f01
--- /dev/null
+++ b/common/config/.gitignore
@@ -0,0 +1,2 @@
+main-local.php
+params-local.php
diff --git a/common/config/bootstrap.php b/common/config/bootstrap.php
new file mode 100644
index 0000000..ecc13e5
--- /dev/null
+++ b/common/config/bootstrap.php
@@ -0,0 +1,5 @@
+ dirname(dirname(__DIR__)) . '/vendor',
+ 'components' => [
+ 'cache' => [
+ 'class' => 'yii\caching\FileCache',
+ ],
+ ],
+];
diff --git a/common/config/params.php b/common/config/params.php
new file mode 100644
index 0000000..4ec9ba6
--- /dev/null
+++ b/common/config/params.php
@@ -0,0 +1,6 @@
+ 'admin@example.com',
+ 'supportEmail' => 'support@example.com',
+ 'user.passwordResetTokenExpire' => 3600,
+];
diff --git a/common/mail/layouts/html.php b/common/mail/layouts/html.php
new file mode 100644
index 0000000..bddbc61
--- /dev/null
+++ b/common/mail/layouts/html.php
@@ -0,0 +1,22 @@
+
+beginPage() ?>
+
+
+
+
+ = Html::encode($this->title) ?>
+ head() ?>
+
+
+ beginBody() ?>
+ = $content ?>
+ endBody() ?>
+
+
+endPage() ?>
diff --git a/common/mail/layouts/text.php b/common/mail/layouts/text.php
new file mode 100644
index 0000000..7087cea
--- /dev/null
+++ b/common/mail/layouts/text.php
@@ -0,0 +1,12 @@
+
+beginPage() ?>
+beginBody() ?>
+= $content ?>
+endBody() ?>
+endPage() ?>
diff --git a/common/mail/passwordResetToken-html.php b/common/mail/passwordResetToken-html.php
new file mode 100644
index 0000000..f3daf49
--- /dev/null
+++ b/common/mail/passwordResetToken-html.php
@@ -0,0 +1,15 @@
+urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]);
+?>
+
+
Hello = Html::encode($user->username) ?>,
+
+
Follow the link below to reset your password:
+
+
= Html::a(Html::encode($resetLink), $resetLink) ?>
+
diff --git a/common/mail/passwordResetToken-text.php b/common/mail/passwordResetToken-text.php
new file mode 100644
index 0000000..244c0cb
--- /dev/null
+++ b/common/mail/passwordResetToken-text.php
@@ -0,0 +1,12 @@
+urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]);
+?>
+Hello = $user->username ?>,
+
+Follow the link below to reset your password:
+
+= $resetLink ?>
diff --git a/common/models/LoginForm.php b/common/models/LoginForm.php
new file mode 100644
index 0000000..afc1c23
--- /dev/null
+++ b/common/models/LoginForm.php
@@ -0,0 +1,78 @@
+hasErrors()) {
+ $user = $this->getUser();
+ if (!$user || !$user->validatePassword($this->password)) {
+ $this->addError($attribute, 'Incorrect username or password.');
+ }
+ }
+ }
+
+ /**
+ * Logs in a user using the provided username and password.
+ *
+ * @return boolean whether the user is logged in successfully
+ */
+ public function login()
+ {
+ if ($this->validate()) {
+ return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Finds user by [[username]]
+ *
+ * @return User|null
+ */
+ protected function getUser()
+ {
+ if ($this->_user === null) {
+ $this->_user = User::findByUsername($this->username);
+ }
+
+ return $this->_user;
+ }
+}
diff --git a/common/models/User.php b/common/models/User.php
new file mode 100644
index 0000000..ce78fcd
--- /dev/null
+++ b/common/models/User.php
@@ -0,0 +1,188 @@
+ self::STATUS_ACTIVE],
+ ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function findIdentity($id)
+ {
+ return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function findIdentityByAccessToken($token, $type = null)
+ {
+ throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
+ }
+
+ /**
+ * Finds user by username
+ *
+ * @param string $username
+ * @return static|null
+ */
+ public static function findByUsername($username)
+ {
+ return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
+ }
+
+ /**
+ * Finds user by password reset token
+ *
+ * @param string $token password reset token
+ * @return static|null
+ */
+ public static function findByPasswordResetToken($token)
+ {
+ if (!static::isPasswordResetTokenValid($token)) {
+ return null;
+ }
+
+ return static::findOne([
+ 'password_reset_token' => $token,
+ 'status' => self::STATUS_ACTIVE,
+ ]);
+ }
+
+ /**
+ * Finds out if password reset token is valid
+ *
+ * @param string $token password reset token
+ * @return boolean
+ */
+ public static function isPasswordResetTokenValid($token)
+ {
+ if (empty($token)) {
+ return false;
+ }
+
+ $timestamp = (int) substr($token, strrpos($token, '_') + 1);
+ $expire = Yii::$app->params['user.passwordResetTokenExpire'];
+ return $timestamp + $expire >= time();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getId()
+ {
+ return $this->getPrimaryKey();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getAuthKey()
+ {
+ return $this->auth_key;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function validateAuthKey($authKey)
+ {
+ return $this->getAuthKey() === $authKey;
+ }
+
+ /**
+ * Validates password
+ *
+ * @param string $password password to validate
+ * @return boolean if password provided is valid for current user
+ */
+ public function validatePassword($password)
+ {
+ return Yii::$app->security->validatePassword($password, $this->password_hash);
+ }
+
+ /**
+ * Generates password hash from password and sets it to the model
+ *
+ * @param string $password
+ */
+ public function setPassword($password)
+ {
+ $this->password_hash = Yii::$app->security->generatePasswordHash($password);
+ }
+
+ /**
+ * Generates "remember me" authentication key
+ */
+ public function generateAuthKey()
+ {
+ $this->auth_key = Yii::$app->security->generateRandomString();
+ }
+
+ /**
+ * Generates new password reset token
+ */
+ public function generatePasswordResetToken()
+ {
+ $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
+ }
+
+ /**
+ * Removes password reset token
+ */
+ public function removePasswordResetToken()
+ {
+ $this->password_reset_token = null;
+ }
+}
diff --git a/common/widgets/Alert.php b/common/widgets/Alert.php
new file mode 100644
index 0000000..8f1e590
--- /dev/null
+++ b/common/widgets/Alert.php
@@ -0,0 +1,79 @@
+session->setFlash('error', 'This is the message');
+ * \Yii::$app->session->setFlash('success', 'This is the message');
+ * \Yii::$app->session->setFlash('info', 'This is the message');
+ * ```
+ *
+ * Multiple messages could be set as follows:
+ *
+ * ```php
+ * \Yii::$app->session->setFlash('error', ['Error 1', 'Error 2']);
+ * ```
+ *
+ * @author Kartik Visweswaran
+ * @author Alexander Makarov
+ */
+class Alert extends \yii\bootstrap\Widget
+{
+ /**
+ * @var array the alert types configuration for the flash messages.
+ * This array is setup as $key => $value, where:
+ * - $key is the name of the session flash variable
+ * - $value is the bootstrap alert type (i.e. danger, success, info, warning)
+ */
+ public $alertTypes = [
+ 'error' => 'alert-danger',
+ 'danger' => 'alert-danger',
+ 'success' => 'alert-success',
+ 'info' => 'alert-info',
+ 'warning' => 'alert-warning'
+ ];
+
+ /**
+ * @var array the options for rendering the close button tag.
+ */
+ public $closeButton = [];
+
+ public function init()
+ {
+ parent::init();
+
+ $session = \Yii::$app->session;
+ $flashes = $session->getAllFlashes();
+ $appendCss = isset($this->options['class']) ? ' ' . $this->options['class'] : '';
+
+ foreach ($flashes as $type => $data) {
+ if (isset($this->alertTypes[$type])) {
+ $data = (array) $data;
+ foreach ($data as $i => $message) {
+ /* initialize css class for each alert box */
+ $this->options['class'] = $this->alertTypes[$type] . $appendCss;
+
+ /* assign unique id to each alert box */
+ $this->options['id'] = $this->getId() . '-' . $type . '-' . $i;
+
+ echo \yii\bootstrap\Alert::widget([
+ 'body' => $message,
+ 'closeButton' => $this->closeButton,
+ 'options' => $this->options,
+ ]);
+ }
+
+ $session->removeFlash($type);
+ }
+ }
+ }
+}
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..22993b0
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,37 @@
+{
+ "name": "yiisoft/yii2-app-advanced",
+ "description": "Yii 2 Advanced Project Template",
+ "keywords": ["yii2", "framework", "advanced", "project template"],
+ "homepage": "http://www.yiiframework.com/",
+ "type": "project",
+ "license": "BSD-3-Clause",
+ "support": {
+ "issues": "https://github.com/yiisoft/yii2/issues?state=open",
+ "forum": "http://www.yiiframework.com/forum/",
+ "wiki": "http://www.yiiframework.com/wiki/",
+ "irc": "irc://irc.freenode.net/yii",
+ "source": "https://github.com/yiisoft/yii2"
+ },
+ "minimum-stability": "stable",
+ "require": {
+ "php": ">=5.4.0",
+ "yiisoft/yii2": ">=2.0.6",
+ "yiisoft/yii2-bootstrap": "*",
+ "yiisoft/yii2-swiftmailer": "*"
+ },
+ "require-dev": {
+ "yiisoft/yii2-codeception": "*",
+ "yiisoft/yii2-debug": "*",
+ "yiisoft/yii2-gii": "*",
+ "yiisoft/yii2-faker": "*"
+ },
+ "config": {
+ "process-timeout": 1800
+ },
+ "extra": {
+ "asset-installer-paths": {
+ "npm-asset-library": "vendor/npm",
+ "bower-asset-library": "vendor/bower"
+ }
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..8ff5113
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,924 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "hash": "8580bd82955b1fbb80d47024e184056e",
+ "packages": [
+ {
+ "name": "bower-asset/bootstrap",
+ "version": "v3.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twbs/bootstrap.git",
+ "reference": "16b48259a62f576e52c903c476bd42b90ab22482"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twbs/bootstrap/zipball/16b48259a62f576e52c903c476bd42b90ab22482",
+ "reference": "16b48259a62f576e52c903c476bd42b90ab22482",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": ">=1.9.1"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": [
+ "less/bootstrap.less",
+ "dist/js/bootstrap.js"
+ ],
+ "bower-asset-ignore": [
+ "/.*",
+ "_config.yml",
+ "CNAME",
+ "composer.json",
+ "CONTRIBUTING.md",
+ "docs",
+ "js/tests",
+ "test-infra"
+ ]
+ },
+ "license": [
+ "MIT"
+ ],
+ "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
+ "keywords": [
+ "css",
+ "framework",
+ "front-end",
+ "js",
+ "less",
+ "mobile-first",
+ "responsive",
+ "web"
+ ]
+ },
+ {
+ "name": "bower-asset/jquery",
+ "version": "2.1.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jquery/jquery.git",
+ "reference": "7751e69b615c6eca6f783a81e292a55725af6b85"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jquery/jquery/zipball/7751e69b615c6eca6f783a81e292a55725af6b85",
+ "reference": "7751e69b615c6eca6f783a81e292a55725af6b85",
+ "shasum": ""
+ },
+ "require-dev": {
+ "bower-asset/qunit": "1.14.0",
+ "bower-asset/requirejs": "2.1.10",
+ "bower-asset/sinon": "1.8.1",
+ "bower-asset/sizzle": "2.1.1-patch2"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": "dist/jquery.js",
+ "bower-asset-ignore": [
+ "**/.*",
+ "build",
+ "dist/cdn",
+ "speed",
+ "test",
+ "*.md",
+ "AUTHORS.txt",
+ "Gruntfile.js",
+ "package.json"
+ ]
+ },
+ "license": [
+ "MIT"
+ ],
+ "keywords": [
+ "javascript",
+ "jquery",
+ "library"
+ ]
+ },
+ {
+ "name": "bower-asset/jquery.inputmask",
+ "version": "3.1.63",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/RobinHerbots/jquery.inputmask.git",
+ "reference": "c40c7287eadc31e341ebbf0c02352eb55b9cbc48"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/RobinHerbots/jquery.inputmask/zipball/c40c7287eadc31e341ebbf0c02352eb55b9cbc48",
+ "reference": "c40c7287eadc31e341ebbf0c02352eb55b9cbc48",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": ">=1.7"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": [
+ "./dist/inputmask/jquery.inputmask.js",
+ "./dist/inputmask/jquery.inputmask.extensions.js",
+ "./dist/inputmask/jquery.inputmask.date.extensions.js",
+ "./dist/inputmask/jquery.inputmask.numeric.extensions.js",
+ "./dist/inputmask/jquery.inputmask.phone.extensions.js",
+ "./dist/inputmask/jquery.inputmask.regex.extensions.js"
+ ],
+ "bower-asset-ignore": [
+ "**/.*",
+ "qunit/",
+ "nuget/",
+ "tools/",
+ "js/",
+ "*.md",
+ "build.properties",
+ "build.xml",
+ "jquery.inputmask.jquery.json"
+ ]
+ },
+ "license": [
+ "http://opensource.org/licenses/mit-license.php"
+ ],
+ "description": "jquery.inputmask is a jquery plugin which create an input mask.",
+ "keywords": [
+ "form",
+ "input",
+ "inputmask",
+ "jquery",
+ "mask",
+ "plugins"
+ ]
+ },
+ {
+ "name": "bower-asset/punycode",
+ "version": "v1.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/bestiejs/punycode.js.git",
+ "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/bestiejs/punycode.js/zipball/38c8d3131a82567bfef18da09f7f4db68c84f8a3",
+ "reference": "38c8d3131a82567bfef18da09f7f4db68c84f8a3",
+ "shasum": ""
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": "punycode.js",
+ "bower-asset-ignore": [
+ "coverage",
+ "tests",
+ ".*",
+ "component.json",
+ "Gruntfile.js",
+ "node_modules",
+ "package.json"
+ ]
+ }
+ },
+ {
+ "name": "bower-asset/yii2-pjax",
+ "version": "v2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/jquery-pjax.git",
+ "reference": "3f20897307cca046fca5323b318475ae9dac0ca0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/jquery-pjax/zipball/3f20897307cca046fca5323b318475ae9dac0ca0",
+ "reference": "3f20897307cca046fca5323b318475ae9dac0ca0",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": ">=1.8"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": "./jquery.pjax.js",
+ "bower-asset-ignore": [
+ ".travis.yml",
+ "Gemfile",
+ "Gemfile.lock",
+ "vendor/",
+ "script/",
+ "test/"
+ ]
+ },
+ "license": [
+ "MIT"
+ ]
+ },
+ {
+ "name": "cebe/markdown",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/cebe/markdown.git",
+ "reference": "54a2c49de31cc44e864ebf0500a35ef21d0010b2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/cebe/markdown/zipball/54a2c49de31cc44e864ebf0500a35ef21d0010b2",
+ "reference": "54a2c49de31cc44e864ebf0500a35ef21d0010b2",
+ "shasum": ""
+ },
+ "require": {
+ "lib-pcre": "*",
+ "php": ">=5.4.0"
+ },
+ "require-dev": {
+ "cebe/indent": "*",
+ "facebook/xhprof": "*@dev",
+ "phpunit/phpunit": "4.1.*"
+ },
+ "bin": [
+ "bin/markdown"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "cebe\\markdown\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Carsten Brandt",
+ "email": "mail@cebe.cc",
+ "homepage": "http://cebe.cc/",
+ "role": "Creator"
+ }
+ ],
+ "description": "A super fast, highly extensible markdown parser for PHP",
+ "homepage": "https://github.com/cebe/markdown#readme",
+ "keywords": [
+ "extensible",
+ "fast",
+ "gfm",
+ "markdown",
+ "markdown-extra"
+ ],
+ "time": "2015-03-06 05:28:07"
+ },
+ {
+ "name": "ezyang/htmlpurifier",
+ "version": "v4.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ezyang/htmlpurifier.git",
+ "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/6f389f0f25b90d0b495308efcfa073981177f0fd",
+ "reference": "6f389f0f25b90d0b495308efcfa073981177f0fd",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.2"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "HTMLPurifier": "library/"
+ },
+ "files": [
+ "library/HTMLPurifier.composer.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "LGPL"
+ ],
+ "authors": [
+ {
+ "name": "Edward Z. Yang",
+ "email": "admin@htmlpurifier.org",
+ "homepage": "http://ezyang.com"
+ }
+ ],
+ "description": "Standards compliant HTML filter written in PHP",
+ "homepage": "http://htmlpurifier.org/",
+ "keywords": [
+ "html"
+ ],
+ "time": "2013-11-30 08:25:19"
+ },
+ {
+ "name": "swiftmailer/swiftmailer",
+ "version": "v5.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/swiftmailer/swiftmailer.git",
+ "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/0697e6aa65c83edf97bb0f23d8763f94e3f11421",
+ "reference": "0697e6aa65c83edf97bb0f23d8763f94e3f11421",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "mockery/mockery": "~0.9.1,<0.9.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.4-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "lib/swift_required.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Chris Corbyn"
+ },
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "description": "Swiftmailer, free feature-rich PHP mailer",
+ "homepage": "http://swiftmailer.org",
+ "keywords": [
+ "email",
+ "mail",
+ "mailer"
+ ],
+ "time": "2015-06-06 14:19:39"
+ },
+ {
+ "name": "yiisoft/yii2",
+ "version": "2.0.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-framework.git",
+ "reference": "f42b2eb80f61992438661b01d0d74c6738e2ff38"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-framework/zipball/f42b2eb80f61992438661b01d0d74c6738e2ff38",
+ "reference": "f42b2eb80f61992438661b01d0d74c6738e2ff38",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": "2.1.*@stable | 1.11.*@stable",
+ "bower-asset/jquery.inputmask": "3.1.*",
+ "bower-asset/punycode": "1.3.*",
+ "bower-asset/yii2-pjax": ">=2.0.1",
+ "cebe/markdown": "~1.0.0 | ~1.1.0",
+ "ext-mbstring": "*",
+ "ezyang/htmlpurifier": "4.6.*",
+ "lib-pcre": "*",
+ "php": ">=5.4.0",
+ "yiisoft/yii2-composer": "*"
+ },
+ "bin": [
+ "yii"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Qiang Xue",
+ "email": "qiang.xue@gmail.com",
+ "homepage": "http://www.yiiframework.com/",
+ "role": "Founder and project lead"
+ },
+ {
+ "name": "Alexander Makarov",
+ "email": "sam@rmcreative.ru",
+ "homepage": "http://rmcreative.ru/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Maurizio Domba",
+ "homepage": "http://mdomba.info/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Carsten Brandt",
+ "email": "mail@cebe.cc",
+ "homepage": "http://cebe.cc/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Timur Ruziev",
+ "email": "resurtm@gmail.com",
+ "homepage": "http://resurtm.com/",
+ "role": "Core framework development"
+ },
+ {
+ "name": "Paul Klimov",
+ "email": "klimov.paul@gmail.com",
+ "role": "Core framework development"
+ }
+ ],
+ "description": "Yii PHP Framework Version 2",
+ "homepage": "http://www.yiiframework.com/",
+ "keywords": [
+ "framework",
+ "yii2"
+ ],
+ "time": "2015-08-05 22:00:30"
+ },
+ {
+ "name": "yiisoft/yii2-bootstrap",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-bootstrap.git",
+ "reference": "1b6b1e61cf91c3cdd517d6a7e71d30bb212e4af0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-bootstrap/zipball/1b6b1e61cf91c3cdd517d6a7e71d30bb212e4af0",
+ "reference": "1b6b1e61cf91c3cdd517d6a7e71d30bb212e4af0",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/bootstrap": "3.3.* | 3.2.* | 3.1.*",
+ "yiisoft/yii2": ">=2.0.4"
+ },
+ "type": "yii2-extension",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ },
+ "asset-installer-paths": {
+ "npm-asset-library": "vendor/npm",
+ "bower-asset-library": "vendor/bower"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\bootstrap\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Qiang Xue",
+ "email": "qiang.xue@gmail.com"
+ }
+ ],
+ "description": "The Twitter Bootstrap extension for the Yii framework",
+ "keywords": [
+ "bootstrap",
+ "yii2"
+ ],
+ "time": "2015-05-10 22:08:17"
+ },
+ {
+ "name": "yiisoft/yii2-composer",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-composer.git",
+ "reference": "ca8d23707ae47d20b0454e4b135c156f6da6d7be"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-composer/zipball/ca8d23707ae47d20b0454e4b135c156f6da6d7be",
+ "reference": "ca8d23707ae47d20b0454e4b135c156f6da6d7be",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "1.0.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "yii\\composer\\Plugin",
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\composer\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Qiang Xue",
+ "email": "qiang.xue@gmail.com"
+ }
+ ],
+ "description": "The composer plugin for Yii extension installer",
+ "keywords": [
+ "composer",
+ "extension installer",
+ "yii2"
+ ],
+ "time": "2015-03-01 06:22:44"
+ },
+ {
+ "name": "yiisoft/yii2-swiftmailer",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-swiftmailer.git",
+ "reference": "4ec435a89e30b203cea99770910fb5499cb3627a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-swiftmailer/zipball/4ec435a89e30b203cea99770910fb5499cb3627a",
+ "reference": "4ec435a89e30b203cea99770910fb5499cb3627a",
+ "shasum": ""
+ },
+ "require": {
+ "swiftmailer/swiftmailer": "~5.0",
+ "yiisoft/yii2": ">=2.0.4"
+ },
+ "type": "yii2-extension",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\swiftmailer\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Paul Klimov",
+ "email": "klimov.paul@gmail.com"
+ }
+ ],
+ "description": "The SwiftMailer integration for the Yii framework",
+ "keywords": [
+ "email",
+ "mail",
+ "mailer",
+ "swift",
+ "swiftmailer",
+ "yii2"
+ ],
+ "time": "2015-05-10 22:12:32"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "bower-asset/typeahead.js",
+ "version": "v0.10.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twitter/typeahead.js.git",
+ "reference": "5f198b87d1af845da502ea9df93a5e84801ce742"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twitter/typeahead.js/zipball/5f198b87d1af845da502ea9df93a5e84801ce742",
+ "reference": "5f198b87d1af845da502ea9df93a5e84801ce742",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/jquery": ">=1.7"
+ },
+ "require-dev": {
+ "bower-asset/jasmine-ajax": "~1.3.1",
+ "bower-asset/jasmine-jquery": "~1.5.2",
+ "bower-asset/jquery": "~1.7"
+ },
+ "type": "bower-asset-library",
+ "extra": {
+ "bower-asset-main": "dist/typeahead.bundle.js"
+ }
+ },
+ {
+ "name": "fzaninotto/faker",
+ "version": "v1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/fzaninotto/Faker.git",
+ "reference": "d0190b156bcca848d401fb80f31f504f37141c8d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/d0190b156bcca848d401fb80f31f504f37141c8d",
+ "reference": "d0190b156bcca848d401fb80f31f504f37141c8d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "~4.0",
+ "squizlabs/php_codesniffer": "~1.5"
+ },
+ "suggest": {
+ "ext-intl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.5.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Faker\\": "src/Faker/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "François Zaninotto"
+ }
+ ],
+ "description": "Faker is a PHP library that generates fake data for you.",
+ "keywords": [
+ "data",
+ "faker",
+ "fixtures"
+ ],
+ "time": "2015-05-29 06:29:14"
+ },
+ {
+ "name": "phpspec/php-diff",
+ "version": "v1.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpspec/php-diff.git",
+ "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpspec/php-diff/zipball/30e103d19519fe678ae64a60d77884ef3d71b28a",
+ "reference": "30e103d19519fe678ae64a60d77884ef3d71b28a",
+ "shasum": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Diff": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Chris Boulton",
+ "homepage": "http://github.com/chrisboulton",
+ "role": "Original developer"
+ }
+ ],
+ "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).",
+ "time": "2013-11-01 13:02:21"
+ },
+ {
+ "name": "yiisoft/yii2-codeception",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-codeception.git",
+ "reference": "de5007e7a99359597abbfe1c88dca3ce620061c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-codeception/zipball/de5007e7a99359597abbfe1c88dca3ce620061c5",
+ "reference": "de5007e7a99359597abbfe1c88dca3ce620061c5",
+ "shasum": ""
+ },
+ "require": {
+ "yiisoft/yii2": ">=2.0.4"
+ },
+ "type": "yii2-extension",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\codeception\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Mark Jebri",
+ "email": "mark.github@yandex.ru"
+ }
+ ],
+ "description": "The Codeception integration for the Yii framework",
+ "keywords": [
+ "codeception",
+ "yii2"
+ ],
+ "time": "2015-05-10 22:08:30"
+ },
+ {
+ "name": "yiisoft/yii2-debug",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-debug.git",
+ "reference": "5c7081b2be71c61d3a50d978b31edc3e0b6f2f97"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-debug/zipball/5c7081b2be71c61d3a50d978b31edc3e0b6f2f97",
+ "reference": "5c7081b2be71c61d3a50d978b31edc3e0b6f2f97",
+ "shasum": ""
+ },
+ "require": {
+ "yiisoft/yii2": ">=2.0.4",
+ "yiisoft/yii2-bootstrap": "*"
+ },
+ "type": "yii2-extension",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\debug\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Qiang Xue",
+ "email": "qiang.xue@gmail.com"
+ }
+ ],
+ "description": "The debugger extension for the Yii framework",
+ "keywords": [
+ "debug",
+ "debugger",
+ "yii2"
+ ],
+ "time": "2015-05-10 22:08:56"
+ },
+ {
+ "name": "yiisoft/yii2-faker",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-faker.git",
+ "reference": "b88ca69ee226a3610b2c26c026c3203d7ac50f6c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-faker/zipball/b88ca69ee226a3610b2c26c026c3203d7ac50f6c",
+ "reference": "b88ca69ee226a3610b2c26c026c3203d7ac50f6c",
+ "shasum": ""
+ },
+ "require": {
+ "fzaninotto/faker": "*",
+ "yiisoft/yii2": "*"
+ },
+ "type": "yii2-extension",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\faker\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Mark Jebri",
+ "email": "mark.github@yandex.ru"
+ }
+ ],
+ "description": "Fixture generator. The Faker integration for the Yii framework.",
+ "keywords": [
+ "Fixture",
+ "faker",
+ "yii2"
+ ],
+ "time": "2015-03-01 06:22:44"
+ },
+ {
+ "name": "yiisoft/yii2-gii",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/yiisoft/yii2-gii.git",
+ "reference": "e5a023e8779bd774194842ec1b8fb4917cf04007"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/yiisoft/yii2-gii/zipball/e5a023e8779bd774194842ec1b8fb4917cf04007",
+ "reference": "e5a023e8779bd774194842ec1b8fb4917cf04007",
+ "shasum": ""
+ },
+ "require": {
+ "bower-asset/typeahead.js": "0.10.*",
+ "phpspec/php-diff": ">=1.0.2",
+ "yiisoft/yii2": ">=2.0.4",
+ "yiisoft/yii2-bootstrap": "~2.0"
+ },
+ "type": "yii2-extension",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ },
+ "asset-installer-paths": {
+ "npm-asset-library": "vendor/npm",
+ "bower-asset-library": "vendor/bower"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "yii\\gii\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Qiang Xue",
+ "email": "qiang.xue@gmail.com"
+ }
+ ],
+ "description": "The Gii extension for the Yii framework",
+ "keywords": [
+ "code generator",
+ "gii",
+ "yii2"
+ ],
+ "time": "2015-05-10 22:09:31"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=5.4.0"
+ },
+ "platform-dev": []
+}
diff --git a/console/config/.gitignore b/console/config/.gitignore
new file mode 100644
index 0000000..20da318
--- /dev/null
+++ b/console/config/.gitignore
@@ -0,0 +1,2 @@
+main-local.php
+params-local.php
\ No newline at end of file
diff --git a/console/config/bootstrap.php b/console/config/bootstrap.php
new file mode 100644
index 0000000..b3d9bbc
--- /dev/null
+++ b/console/config/bootstrap.php
@@ -0,0 +1 @@
+ 'app-console',
+ 'basePath' => dirname(__DIR__),
+ 'bootstrap' => ['log'],
+ 'controllerNamespace' => 'console\controllers',
+ 'components' => [
+ 'log' => [
+ 'targets' => [
+ [
+ 'class' => 'yii\log\FileTarget',
+ 'levels' => ['error', 'warning'],
+ ],
+ ],
+ ],
+ ],
+ 'params' => $params,
+];
diff --git a/console/config/params.php b/console/config/params.php
new file mode 100644
index 0000000..7f754b9
--- /dev/null
+++ b/console/config/params.php
@@ -0,0 +1,4 @@
+ 'admin@example.com',
+];
diff --git a/console/controllers/.gitkeep b/console/controllers/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/console/controllers/.gitkeep
diff --git a/console/migrations/m130524_201442_init.php b/console/migrations/m130524_201442_init.php
new file mode 100644
index 0000000..81a322a
--- /dev/null
+++ b/console/migrations/m130524_201442_init.php
@@ -0,0 +1,34 @@
+db->driverName === 'mysql') {
+ // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
+ $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
+ }
+
+ $this->createTable('{{%user}}', [
+ 'id' => $this->primaryKey(),
+ 'username' => $this->string()->notNull()->unique(),
+ 'auth_key' => $this->string(32)->notNull(),
+ 'password_hash' => $this->string()->notNull(),
+ 'password_reset_token' => $this->string()->unique(),
+ 'email' => $this->string()->notNull()->unique(),
+
+ 'status' => $this->smallInteger()->notNull()->defaultValue(10),
+ 'created_at' => $this->integer()->notNull(),
+ 'updated_at' => $this->integer()->notNull(),
+ ], $tableOptions);
+ }
+
+ public function down()
+ {
+ $this->dropTable('{{%user}}');
+ }
+}
diff --git a/console/models/.gitkeep b/console/models/.gitkeep
new file mode 100644
index 0000000..72e8ffc
--- /dev/null
+++ b/console/models/.gitkeep
@@ -0,0 +1 @@
+*
diff --git a/console/runtime/.gitignore b/console/runtime/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/console/runtime/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/environments/dev/backend/config/main-local.php b/environments/dev/backend/config/main-local.php
new file mode 100644
index 0000000..d9a8ceb
--- /dev/null
+++ b/environments/dev/backend/config/main-local.php
@@ -0,0 +1,25 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
+
+if (!YII_ENV_TEST) {
+ // configuration adjustments for 'dev' environment
+ $config['bootstrap'][] = 'debug';
+ $config['modules']['debug'] = [
+ 'class' => 'yii\debug\Module',
+ ];
+
+ $config['bootstrap'][] = 'gii';
+ $config['modules']['gii'] = [
+ 'class' => 'yii\gii\Module',
+ ];
+}
+
+return $config;
diff --git a/environments/dev/backend/config/params-local.php b/environments/dev/backend/config/params-local.php
new file mode 100644
index 0000000..d0b9c34
--- /dev/null
+++ b/environments/dev/backend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/dev/backend/web/index.php b/environments/dev/backend/web/index.php
new file mode 100644
index 0000000..6038167
--- /dev/null
+++ b/environments/dev/backend/web/index.php
@@ -0,0 +1,18 @@
+run();
diff --git a/environments/dev/common/config/main-local.php b/environments/dev/common/config/main-local.php
new file mode 100644
index 0000000..43db30e
--- /dev/null
+++ b/environments/dev/common/config/main-local.php
@@ -0,0 +1,20 @@
+ [
+ 'db' => [
+ 'class' => 'yii\db\Connection',
+ 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ ],
+ 'mailer' => [
+ 'class' => 'yii\swiftmailer\Mailer',
+ 'viewPath' => '@common/mail',
+ // send all mails to a file by default. You have to set
+ // 'useFileTransport' to false and configure a transport
+ // for the mailer to send real emails.
+ 'useFileTransport' => true,
+ ],
+ ],
+];
diff --git a/environments/dev/common/config/params-local.php b/environments/dev/common/config/params-local.php
new file mode 100644
index 0000000..d0b9c34
--- /dev/null
+++ b/environments/dev/common/config/params-local.php
@@ -0,0 +1,3 @@
+ ['gii'],
+ 'modules' => [
+ 'gii' => 'yii\gii\Module',
+ ],
+];
diff --git a/environments/dev/console/config/params-local.php b/environments/dev/console/config/params-local.php
new file mode 100644
index 0000000..d0b9c34
--- /dev/null
+++ b/environments/dev/console/config/params-local.php
@@ -0,0 +1,3 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
+
+if (!YII_ENV_TEST) {
+ // configuration adjustments for 'dev' environment
+ $config['bootstrap'][] = 'debug';
+ $config['modules']['debug'] = 'yii\debug\Module';
+
+ $config['bootstrap'][] = 'gii';
+ $config['modules']['gii'] = 'yii\gii\Module';
+}
+
+return $config;
diff --git a/environments/dev/frontend/config/params-local.php b/environments/dev/frontend/config/params-local.php
new file mode 100644
index 0000000..d0b9c34
--- /dev/null
+++ b/environments/dev/frontend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/dev/frontend/web/index.php b/environments/dev/frontend/web/index.php
new file mode 100644
index 0000000..6038167
--- /dev/null
+++ b/environments/dev/frontend/web/index.php
@@ -0,0 +1,18 @@
+run();
diff --git a/environments/dev/yii b/environments/dev/yii
new file mode 100644
index 0000000..6f0c6d2
--- /dev/null
+++ b/environments/dev/yii
@@ -0,0 +1,28 @@
+#!/usr/bin/env php
+run();
+exit($exitCode);
diff --git a/environments/index.php b/environments/index.php
new file mode 100644
index 0000000..19c989d
--- /dev/null
+++ b/environments/index.php
@@ -0,0 +1,65 @@
+ [
+ * 'path' => 'directory storing the local files',
+ * 'skipFiles' => [
+ * // list of files that should only copied once and skipped if they already exist
+ * ],
+ * 'setWritable' => [
+ * // list of directories that should be set writable
+ * ],
+ * 'setExecutable' => [
+ * // list of files that should be set executable
+ * ],
+ * 'setCookieValidationKey' => [
+ * // list of config files that need to be inserted with automatically generated cookie validation keys
+ * ],
+ * 'createSymlink' => [
+ * // list of symlinks to be created. Keys are symlinks, and values are the targets.
+ * ],
+ * ],
+ * ];
+ * ```
+ */
+return [
+ 'Development' => [
+ 'path' => 'dev',
+ 'setWritable' => [
+ 'backend/runtime',
+ 'backend/web/assets',
+ 'frontend/runtime',
+ 'frontend/web/assets',
+ ],
+ 'setExecutable' => [
+ 'yii',
+ 'tests/codeception/bin/yii',
+ ],
+ 'setCookieValidationKey' => [
+ 'backend/config/main-local.php',
+ 'frontend/config/main-local.php',
+ ],
+ ],
+ 'Production' => [
+ 'path' => 'prod',
+ 'setWritable' => [
+ 'backend/runtime',
+ 'backend/web/assets',
+ 'frontend/runtime',
+ 'frontend/web/assets',
+ ],
+ 'setExecutable' => [
+ 'yii',
+ ],
+ 'setCookieValidationKey' => [
+ 'backend/config/main-local.php',
+ 'frontend/config/main-local.php',
+ ],
+ ],
+];
diff --git a/environments/prod/backend/config/main-local.php b/environments/prod/backend/config/main-local.php
new file mode 100644
index 0000000..af46ba3
--- /dev/null
+++ b/environments/prod/backend/config/main-local.php
@@ -0,0 +1,9 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
diff --git a/environments/prod/backend/config/params-local.php b/environments/prod/backend/config/params-local.php
new file mode 100644
index 0000000..d0b9c34
--- /dev/null
+++ b/environments/prod/backend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/prod/common/config/main-local.php b/environments/prod/common/config/main-local.php
new file mode 100644
index 0000000..84c4d9f
--- /dev/null
+++ b/environments/prod/common/config/main-local.php
@@ -0,0 +1,16 @@
+ [
+ 'db' => [
+ 'class' => 'yii\db\Connection',
+ 'dsn' => 'mysql:host=localhost;dbname=yii2advanced',
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ ],
+ 'mailer' => [
+ 'class' => 'yii\swiftmailer\Mailer',
+ 'viewPath' => '@common/mail',
+ ],
+ ],
+];
diff --git a/environments/prod/common/config/params-local.php b/environments/prod/common/config/params-local.php
new file mode 100644
index 0000000..d0b9c34
--- /dev/null
+++ b/environments/prod/common/config/params-local.php
@@ -0,0 +1,3 @@
+ [
+ 'request' => [
+ // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
+ 'cookieValidationKey' => '',
+ ],
+ ],
+];
diff --git a/environments/prod/frontend/config/params-local.php b/environments/prod/frontend/config/params-local.php
new file mode 100644
index 0000000..d0b9c34
--- /dev/null
+++ b/environments/prod/frontend/config/params-local.php
@@ -0,0 +1,3 @@
+run();
diff --git a/environments/prod/yii b/environments/prod/yii
new file mode 100644
index 0000000..1fe0342
--- /dev/null
+++ b/environments/prod/yii
@@ -0,0 +1,28 @@
+#!/usr/bin/env php
+run();
+exit($exitCode);
diff --git a/frontend/assets/AppAsset.php b/frontend/assets/AppAsset.php
new file mode 100644
index 0000000..995e3dc
--- /dev/null
+++ b/frontend/assets/AppAsset.php
@@ -0,0 +1,29 @@
+
+ * @since 2.0
+ */
+class AppAsset extends AssetBundle
+{
+ public $basePath = '@webroot';
+ public $baseUrl = '@web';
+ public $css = [
+ 'css/site.css',
+ ];
+ public $js = [
+ ];
+ public $depends = [
+ 'yii\web\YiiAsset',
+ 'yii\bootstrap\BootstrapAsset',
+ ];
+}
diff --git a/frontend/config/.gitignore b/frontend/config/.gitignore
new file mode 100644
index 0000000..20da318
--- /dev/null
+++ b/frontend/config/.gitignore
@@ -0,0 +1,2 @@
+main-local.php
+params-local.php
\ No newline at end of file
diff --git a/frontend/config/bootstrap.php b/frontend/config/bootstrap.php
new file mode 100644
index 0000000..b3d9bbc
--- /dev/null
+++ b/frontend/config/bootstrap.php
@@ -0,0 +1 @@
+ 'app-frontend',
+ 'basePath' => dirname(__DIR__),
+ 'bootstrap' => ['log'],
+ 'controllerNamespace' => 'frontend\controllers',
+ 'components' => [
+ 'user' => [
+ 'identityClass' => 'common\models\User',
+ 'enableAutoLogin' => true,
+ ],
+ 'log' => [
+ 'traceLevel' => YII_DEBUG ? 3 : 0,
+ 'targets' => [
+ [
+ 'class' => 'yii\log\FileTarget',
+ 'levels' => ['error', 'warning'],
+ ],
+ ],
+ ],
+ 'errorHandler' => [
+ 'errorAction' => 'site/error',
+ ],
+ ],
+ 'params' => $params,
+];
diff --git a/frontend/config/params.php b/frontend/config/params.php
new file mode 100644
index 0000000..7f754b9
--- /dev/null
+++ b/frontend/config/params.php
@@ -0,0 +1,4 @@
+ 'admin@example.com',
+];
diff --git a/frontend/controllers/SiteController.php b/frontend/controllers/SiteController.php
new file mode 100644
index 0000000..cf691ae
--- /dev/null
+++ b/frontend/controllers/SiteController.php
@@ -0,0 +1,213 @@
+ [
+ 'class' => AccessControl::className(),
+ 'only' => ['logout', 'signup'],
+ 'rules' => [
+ [
+ 'actions' => ['signup'],
+ 'allow' => true,
+ 'roles' => ['?'],
+ ],
+ [
+ 'actions' => ['logout'],
+ 'allow' => true,
+ 'roles' => ['@'],
+ ],
+ ],
+ ],
+ 'verbs' => [
+ 'class' => VerbFilter::className(),
+ 'actions' => [
+ 'logout' => ['post'],
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function actions()
+ {
+ return [
+ 'error' => [
+ 'class' => 'yii\web\ErrorAction',
+ ],
+ 'captcha' => [
+ 'class' => 'yii\captcha\CaptchaAction',
+ 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
+ ],
+ ];
+ }
+
+ /**
+ * Displays homepage.
+ *
+ * @return mixed
+ */
+ public function actionIndex()
+ {
+ return $this->render('index');
+ }
+
+ /**
+ * Logs in a user.
+ *
+ * @return mixed
+ */
+ public function actionLogin()
+ {
+ if (!\Yii::$app->user->isGuest) {
+ return $this->goHome();
+ }
+
+ $model = new LoginForm();
+ if ($model->load(Yii::$app->request->post()) && $model->login()) {
+ return $this->goBack();
+ } else {
+ return $this->render('login', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Logs out the current user.
+ *
+ * @return mixed
+ */
+ public function actionLogout()
+ {
+ Yii::$app->user->logout();
+
+ return $this->goHome();
+ }
+
+ /**
+ * Displays contact page.
+ *
+ * @return mixed
+ */
+ public function actionContact()
+ {
+ $model = new ContactForm();
+ if ($model->load(Yii::$app->request->post()) && $model->validate()) {
+ if ($model->sendEmail(Yii::$app->params['adminEmail'])) {
+ Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.');
+ } else {
+ Yii::$app->session->setFlash('error', 'There was an error sending email.');
+ }
+
+ return $this->refresh();
+ } else {
+ return $this->render('contact', [
+ 'model' => $model,
+ ]);
+ }
+ }
+
+ /**
+ * Displays about page.
+ *
+ * @return mixed
+ */
+ public function actionAbout()
+ {
+ return $this->render('about');
+ }
+
+ /**
+ * Signs user up.
+ *
+ * @return mixed
+ */
+ public function actionSignup()
+ {
+ $model = new SignupForm();
+ if ($model->load(Yii::$app->request->post())) {
+ if ($user = $model->signup()) {
+ if (Yii::$app->getUser()->login($user)) {
+ return $this->goHome();
+ }
+ }
+ }
+
+ return $this->render('signup', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Requests password reset.
+ *
+ * @return mixed
+ */
+ public function actionRequestPasswordReset()
+ {
+ $model = new PasswordResetRequestForm();
+ if ($model->load(Yii::$app->request->post()) && $model->validate()) {
+ if ($model->sendEmail()) {
+ Yii::$app->session->setFlash('success', 'Check your email for further instructions.');
+
+ return $this->goHome();
+ } else {
+ Yii::$app->session->setFlash('error', 'Sorry, we are unable to reset password for email provided.');
+ }
+ }
+
+ return $this->render('requestPasswordResetToken', [
+ 'model' => $model,
+ ]);
+ }
+
+ /**
+ * Resets password.
+ *
+ * @param string $token
+ * @return mixed
+ * @throws BadRequestHttpException
+ */
+ public function actionResetPassword($token)
+ {
+ try {
+ $model = new ResetPasswordForm($token);
+ } catch (InvalidParamException $e) {
+ throw new BadRequestHttpException($e->getMessage());
+ }
+
+ if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) {
+ Yii::$app->session->setFlash('success', 'New password was saved.');
+
+ return $this->goHome();
+ }
+
+ return $this->render('resetPassword', [
+ 'model' => $model,
+ ]);
+ }
+}
diff --git a/frontend/models/ContactForm.php b/frontend/models/ContactForm.php
new file mode 100644
index 0000000..613abb5
--- /dev/null
+++ b/frontend/models/ContactForm.php
@@ -0,0 +1,59 @@
+ 'Verification Code',
+ ];
+ }
+
+ /**
+ * Sends an email to the specified email address using the information collected by this model.
+ *
+ * @param string $email the target email address
+ * @return boolean whether the email was sent
+ */
+ public function sendEmail($email)
+ {
+ return Yii::$app->mailer->compose()
+ ->setTo($email)
+ ->setFrom([$this->email => $this->name])
+ ->setSubject($this->subject)
+ ->setTextBody($this->body)
+ ->send();
+ }
+}
diff --git a/frontend/models/PasswordResetRequestForm.php b/frontend/models/PasswordResetRequestForm.php
new file mode 100644
index 0000000..20c6810
--- /dev/null
+++ b/frontend/models/PasswordResetRequestForm.php
@@ -0,0 +1,60 @@
+ 'trim'],
+ ['email', 'required'],
+ ['email', 'email'],
+ ['email', 'exist',
+ 'targetClass' => '\common\models\User',
+ 'filter' => ['status' => User::STATUS_ACTIVE],
+ 'message' => 'There is no user with such email.'
+ ],
+ ];
+ }
+
+ /**
+ * Sends an email with a link, for resetting the password.
+ *
+ * @return boolean whether the email was send
+ */
+ public function sendEmail()
+ {
+ /* @var $user User */
+ $user = User::findOne([
+ 'status' => User::STATUS_ACTIVE,
+ 'email' => $this->email,
+ ]);
+
+ if ($user) {
+ if (!User::isPasswordResetTokenValid($user->password_reset_token)) {
+ $user->generatePasswordResetToken();
+ }
+
+ if ($user->save()) {
+ return \Yii::$app->mailer->compose(['html' => 'passwordResetToken-html', 'text' => 'passwordResetToken-text'], ['user' => $user])
+ ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name . ' robot'])
+ ->setTo($this->email)
+ ->setSubject('Password reset for ' . \Yii::$app->name)
+ ->send();
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/frontend/models/ResetPasswordForm.php b/frontend/models/ResetPasswordForm.php
new file mode 100644
index 0000000..dd48f52
--- /dev/null
+++ b/frontend/models/ResetPasswordForm.php
@@ -0,0 +1,65 @@
+_user = User::findByPasswordResetToken($token);
+ if (!$this->_user) {
+ throw new InvalidParamException('Wrong password reset token.');
+ }
+ parent::__construct($config);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function rules()
+ {
+ return [
+ ['password', 'required'],
+ ['password', 'string', 'min' => 6],
+ ];
+ }
+
+ /**
+ * Resets password.
+ *
+ * @return boolean if password was reset.
+ */
+ public function resetPassword()
+ {
+ $user = $this->_user;
+ $user->setPassword($this->password);
+ $user->removePasswordResetToken();
+
+ return $user->save(false);
+ }
+}
diff --git a/frontend/models/SignupForm.php b/frontend/models/SignupForm.php
new file mode 100644
index 0000000..e83963b
--- /dev/null
+++ b/frontend/models/SignupForm.php
@@ -0,0 +1,59 @@
+ 'trim'],
+ ['username', 'required'],
+ ['username', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This username has already been taken.'],
+ ['username', 'string', 'min' => 2, 'max' => 255],
+
+ ['email', 'filter', 'filter' => 'trim'],
+ ['email', 'required'],
+ ['email', 'email'],
+ ['email', 'string', 'max' => 255],
+ ['email', 'unique', 'targetClass' => '\common\models\User', 'message' => 'This email address has already been taken.'],
+
+ ['password', 'required'],
+ ['password', 'string', 'min' => 6],
+ ];
+ }
+
+ /**
+ * Signs user up.
+ *
+ * @return User|null the saved model or null if saving fails
+ */
+ public function signup()
+ {
+ if ($this->validate()) {
+ $user = new User();
+ $user->username = $this->username;
+ $user->email = $this->email;
+ $user->setPassword($this->password);
+ $user->generateAuthKey();
+ if ($user->save()) {
+ return $user;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/frontend/runtime/.gitignore b/frontend/runtime/.gitignore
new file mode 100644
index 0000000..c96a04f
--- /dev/null
+++ b/frontend/runtime/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
\ No newline at end of file
diff --git a/frontend/views/layouts/main.php b/frontend/views/layouts/main.php
new file mode 100644
index 0000000..3e09838
--- /dev/null
+++ b/frontend/views/layouts/main.php
@@ -0,0 +1,79 @@
+
+beginPage() ?>
+
+
+
+
+
+ = Html::csrfMetaTags() ?>
+ = Html::encode($this->title) ?>
+ head() ?>
+
+
+beginBody() ?>
+
+
+ 'My Company',
+ 'brandUrl' => Yii::$app->homeUrl,
+ 'options' => [
+ 'class' => 'navbar-inverse navbar-fixed-top',
+ ],
+ ]);
+ $menuItems = [
+ ['label' => 'Home', 'url' => ['/site/index']],
+ ['label' => 'About', 'url' => ['/site/about']],
+ ['label' => 'Contact', 'url' => ['/site/contact']],
+ ];
+ if (Yii::$app->user->isGuest) {
+ $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']];
+ $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']];
+ } else {
+ $menuItems[] = [
+ 'label' => 'Logout (' . Yii::$app->user->identity->username . ')',
+ 'url' => ['/site/logout'],
+ 'linkOptions' => ['data-method' => 'post']
+ ];
+ }
+ echo Nav::widget([
+ 'options' => ['class' => 'navbar-nav navbar-right'],
+ 'items' => $menuItems,
+ ]);
+ NavBar::end();
+ ?>
+
+
+ = Breadcrumbs::widget([
+ 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
+ ]) ?>
+ = Alert::widget() ?>
+ = $content ?>
+
+
+
+
+
+endBody() ?>
+
+
+endPage() ?>
diff --git a/frontend/views/site/about.php b/frontend/views/site/about.php
new file mode 100644
index 0000000..8eb0764
--- /dev/null
+++ b/frontend/views/site/about.php
@@ -0,0 +1,16 @@
+title = 'About';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
This is the About page. You may modify the following file to customize its content:
+
+
= __FILE__ ?>
+
diff --git a/frontend/views/site/contact.php b/frontend/views/site/contact.php
new file mode 100644
index 0000000..16ebdb2
--- /dev/null
+++ b/frontend/views/site/contact.php
@@ -0,0 +1,45 @@
+title = 'Contact';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
diff --git a/frontend/views/site/error.php b/frontend/views/site/error.php
new file mode 100644
index 0000000..0ba2574
--- /dev/null
+++ b/frontend/views/site/error.php
@@ -0,0 +1,27 @@
+title = $name;
+?>
+
+
+
= Html::encode($this->title) ?>
+
+
+ = nl2br(Html::encode($message)) ?>
+
+
+
+ The above error occurred while the Web server was processing your request.
+
+
+ Please contact us if you think this is a server error. Thank you.
+
+
+
diff --git a/frontend/views/site/index.php b/frontend/views/site/index.php
new file mode 100644
index 0000000..ff41da9
--- /dev/null
+++ b/frontend/views/site/index.php
@@ -0,0 +1,53 @@
+title = 'Автозапчасти, каталог запчастей, запчасти для иномарок в магазине ИталАвто';
+?>
+
+
+
+
Congratulations!
+
+
You have successfully created your Yii-powered application.
+
+
Get started with Yii
+
+
+
+
+
+
+
Heading
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
+ dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
+ ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+ fugiat nulla pariatur.
+
+
Yii Documentation »
+
+
+
Heading
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
+ dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
+ ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+ fugiat nulla pariatur.
+
+
Yii Forum »
+
+
+
Heading
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
+ dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
+ ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
+ fugiat nulla pariatur.
+
+
Yii Extensions »
+
+
+
+
+
diff --git a/frontend/views/site/login.php b/frontend/views/site/login.php
new file mode 100644
index 0000000..fe67ee0
--- /dev/null
+++ b/frontend/views/site/login.php
@@ -0,0 +1,39 @@
+title = 'Login';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out the following fields to login:
+
+
+
+ 'login-form']); ?>
+
+ = $form->field($model, 'username') ?>
+
+ = $form->field($model, 'password')->passwordInput() ?>
+
+ = $form->field($model, 'rememberMe')->checkbox() ?>
+
+
+ If you forgot your password you can = Html::a('reset it', ['site/request-password-reset']) ?>.
+
+
+
+ = Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']) ?>
+
+
+
+
+
+
diff --git a/frontend/views/site/requestPasswordResetToken.php b/frontend/views/site/requestPasswordResetToken.php
new file mode 100644
index 0000000..494ddb3
--- /dev/null
+++ b/frontend/views/site/requestPasswordResetToken.php
@@ -0,0 +1,31 @@
+title = 'Request password reset';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out your email. A link to reset password will be sent there.
+
+
+
+ 'request-password-reset-form']); ?>
+
+ = $form->field($model, 'email') ?>
+
+
+ = Html::submitButton('Send', ['class' => 'btn btn-primary']) ?>
+
+
+
+
+
+
diff --git a/frontend/views/site/resetPassword.php b/frontend/views/site/resetPassword.php
new file mode 100644
index 0000000..8e6d93f
--- /dev/null
+++ b/frontend/views/site/resetPassword.php
@@ -0,0 +1,31 @@
+title = 'Reset password';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please choose your new password:
+
+
+
+ 'reset-password-form']); ?>
+
+ = $form->field($model, 'password')->passwordInput() ?>
+
+
+ = Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>
+
+
+
+
+
+
diff --git a/frontend/views/site/signup.php b/frontend/views/site/signup.php
new file mode 100644
index 0000000..58ccd8e
--- /dev/null
+++ b/frontend/views/site/signup.php
@@ -0,0 +1,35 @@
+title = 'Signup';
+$this->params['breadcrumbs'][] = $this->title;
+?>
+
+
= Html::encode($this->title) ?>
+
+
Please fill out the following fields to signup:
+
+
+
+ 'form-signup']); ?>
+
+ = $form->field($model, 'username') ?>
+
+ = $form->field($model, 'email') ?>
+
+ = $form->field($model, 'password')->passwordInput() ?>
+
+
+ = Html::submitButton('Signup', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>
+
+
+
+
+
+
diff --git a/frontend/web/.gitignore b/frontend/web/.gitignore
new file mode 100644
index 0000000..25c74e6
--- /dev/null
+++ b/frontend/web/.gitignore
@@ -0,0 +1,2 @@
+/index.php
+/index-test.php
diff --git a/frontend/web/.htaccess b/frontend/web/.htaccess
new file mode 100644
index 0000000..35a2d28
--- /dev/null
+++ b/frontend/web/.htaccess
@@ -0,0 +1,8 @@
+RewriteEngine on
+RewriteBase /
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+
+RewriteRule . index.php
+
+Options -Indexes
\ No newline at end of file
diff --git a/frontend/web/assets/.gitignore b/frontend/web/assets/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/frontend/web/assets/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/frontend/web/css/site.css b/frontend/web/css/site.css
new file mode 100644
index 0000000..698be70
--- /dev/null
+++ b/frontend/web/css/site.css
@@ -0,0 +1,91 @@
+html,
+body {
+ height: 100%;
+}
+
+.wrap {
+ min-height: 100%;
+ height: auto;
+ margin: 0 auto -60px;
+ padding: 0 0 60px;
+}
+
+.wrap > .container {
+ padding: 70px 15px 20px;
+}
+
+.footer {
+ height: 60px;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ padding-top: 20px;
+}
+
+.jumbotron {
+ text-align: center;
+ background-color: transparent;
+}
+
+.jumbotron .btn {
+ font-size: 21px;
+ padding: 14px 24px;
+}
+
+.not-set {
+ color: #c55;
+ font-style: italic;
+}
+
+/* add sorting icons to gridview sort links */
+a.asc:after, a.desc:after {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ font-family: 'Glyphicons Halflings';
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+ padding-left: 5px;
+}
+
+a.asc:after {
+ content: /*"\e113"*/ "\e151";
+}
+
+a.desc:after {
+ content: /*"\e114"*/ "\e152";
+}
+
+.sort-numerical a.asc:after {
+ content: "\e153";
+}
+
+.sort-numerical a.desc:after {
+ content: "\e154";
+}
+
+.sort-ordinal a.asc:after {
+ content: "\e155";
+}
+
+.sort-ordinal a.desc:after {
+ content: "\e156";
+}
+
+.grid-view th {
+ white-space: nowrap;
+}
+
+.hint-block {
+ display: block;
+ margin-top: 5px;
+ color: #999;
+}
+
+.error-summary {
+ color: #a94442;
+ background: #fdf7f7;
+ border-left: 3px solid #eed3d7;
+ padding: 10px 20px;
+ margin: 0 0 15px 0;
+}
diff --git a/frontend/web/favicon.ico b/frontend/web/favicon.ico
new file mode 100644
index 0000000..580ed73
Binary files /dev/null and b/frontend/web/favicon.ico differ
diff --git a/frontend/web/robots.txt b/frontend/web/robots.txt
new file mode 100644
index 0000000..6f27bb6
--- /dev/null
+++ b/frontend/web/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow:
\ No newline at end of file
diff --git a/init b/init
new file mode 100644
index 0000000..1b35927
--- /dev/null
+++ b/init
@@ -0,0 +1,209 @@
+#!/usr/bin/env php
+
+ *
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+if (!extension_loaded('openssl')) {
+ die('The OpenSSL PHP extension is required by Yii2.');
+}
+
+$params = getParams();
+$root = str_replace('\\', '/', __DIR__);
+$envs = require("$root/environments/index.php");
+$envNames = array_keys($envs);
+
+echo "Yii Application Initialization Tool v1.0\n\n";
+
+$envName = null;
+if (empty($params['env']) || $params['env'] === '1') {
+ echo "Which environment do you want the application to be initialized in?\n\n";
+ foreach ($envNames as $i => $name) {
+ echo " [$i] $name\n";
+ }
+ echo "\n Your choice [0-" . (count($envs) - 1) . ', or "q" to quit] ';
+ $answer = trim(fgets(STDIN));
+
+ if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) {
+ echo "\n Quit initialization.\n";
+ exit(0);
+ }
+
+ if (isset($envNames[$answer])) {
+ $envName = $envNames[$answer];
+ }
+} else {
+ $envName = $params['env'];
+}
+
+if (!in_array($envName, $envNames)) {
+ $envsList = implode(', ', $envNames);
+ echo "\n $envName is not a valid environment. Try one of the following: $envsList. \n";
+ exit(2);
+}
+
+$env = $envs[$envName];
+
+if (empty($params['env'])) {
+ echo "\n Initialize the application under '{$envNames[$answer]}' environment? [yes|no] ";
+ $answer = trim(fgets(STDIN));
+ if (strncasecmp($answer, 'y', 1)) {
+ echo "\n Quit initialization.\n";
+ exit(0);
+ }
+}
+
+echo "\n Start initialization ...\n\n";
+$files = getFileList("$root/environments/{$env['path']}");
+if (isset($env['skipFiles'])) {
+ $skipFiles = $env['skipFiles'];
+ array_walk($skipFiles, function(&$value) use($env, $root) { $value = "$root/$value"; });
+ $files = array_diff($files, array_intersect_key($env['skipFiles'], array_filter($skipFiles, 'file_exists')));
+}
+$all = false;
+foreach ($files as $file) {
+ if (!copyFile($root, "environments/{$env['path']}/$file", $file, $all, $params)) {
+ break;
+ }
+}
+
+$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable', 'createSymlink'];
+foreach ($callbacks as $callback) {
+ if (!empty($env[$callback])) {
+ $callback($root, $env[$callback]);
+ }
+}
+
+echo "\n ... initialization completed.\n\n";
+
+function getFileList($root, $basePath = '')
+{
+ $files = [];
+ $handle = opendir($root);
+ while (($path = readdir($handle)) !== false) {
+ if ($path === '.git' || $path === '.svn' || $path === '.' || $path === '..') {
+ continue;
+ }
+ $fullPath = "$root/$path";
+ $relativePath = $basePath === '' ? $path : "$basePath/$path";
+ if (is_dir($fullPath)) {
+ $files = array_merge($files, getFileList($fullPath, $relativePath));
+ } else {
+ $files[] = $relativePath;
+ }
+ }
+ closedir($handle);
+ return $files;
+}
+
+function copyFile($root, $source, $target, &$all, $params)
+{
+ if (!is_file($root . '/' . $source)) {
+ echo " skip $target ($source not exist)\n";
+ return true;
+ }
+ if (is_file($root . '/' . $target)) {
+ if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
+ echo " unchanged $target\n";
+ return true;
+ }
+ if ($all) {
+ echo " overwrite $target\n";
+ } else {
+ echo " exist $target\n";
+ echo " ...overwrite? [Yes|No|All|Quit] ";
+
+
+ $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));
+ if (!strncasecmp($answer, 'q', 1)) {
+ return false;
+ } else {
+ if (!strncasecmp($answer, 'y', 1)) {
+ echo " overwrite $target\n";
+ } else {
+ if (!strncasecmp($answer, 'a', 1)) {
+ echo " overwrite $target\n";
+ $all = true;
+ } else {
+ echo " skip $target\n";
+ return true;
+ }
+ }
+ }
+ }
+ file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
+ return true;
+ }
+ echo " generate $target\n";
+ @mkdir(dirname($root . '/' . $target), 0777, true);
+ file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
+ return true;
+}
+
+function getParams()
+{
+ $rawParams = [];
+ if (isset($_SERVER['argv'])) {
+ $rawParams = $_SERVER['argv'];
+ array_shift($rawParams);
+ }
+
+ $params = [];
+ foreach ($rawParams as $param) {
+ if (preg_match('/^--(\w+)(=(.*))?$/', $param, $matches)) {
+ $name = $matches[1];
+ $params[$name] = isset($matches[3]) ? $matches[3] : true;
+ } else {
+ $params[] = $param;
+ }
+ }
+ return $params;
+}
+
+function setWritable($root, $paths)
+{
+ foreach ($paths as $writable) {
+ echo " chmod 0777 $writable\n";
+ @chmod("$root/$writable", 0777);
+ }
+}
+
+function setExecutable($root, $paths)
+{
+ foreach ($paths as $executable) {
+ echo " chmod 0755 $executable\n";
+ @chmod("$root/$executable", 0755);
+ }
+}
+
+function setCookieValidationKey($root, $paths)
+{
+ foreach ($paths as $file) {
+ echo " generate cookie validation key in $file\n";
+ $file = $root . '/' . $file;
+ $length = 32;
+ $bytes = openssl_random_pseudo_bytes($length);
+ $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
+ $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file));
+ file_put_contents($file, $content);
+ }
+}
+
+function createSymlink($root, $links) {
+ foreach ($links as $link => $target) {
+ echo " symlink " . $root . "/" . $target . " " . $root . "/" . $link . "\n";
+ //first removing folders to avoid errors if the folder already exists
+ @rmdir($root . "/" . $link);
+ @symlink($root . "/" . $target, $root . "/" . $link);
+ }
+}
diff --git a/init.bat b/init.bat
new file mode 100644
index 0000000..e50c242
--- /dev/null
+++ b/init.bat
@@ -0,0 +1,20 @@
+@echo off
+
+rem -------------------------------------------------------------
+rem Yii command line init script for Windows.
+rem
+rem @author Qiang Xue
+rem @link http://www.yiiframework.com/
+rem @copyright Copyright (c) 2008 Yii Software LLC
+rem @license http://www.yiiframework.com/license/
+rem -------------------------------------------------------------
+
+@setlocal
+
+set YII_PATH=%~dp0
+
+if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
+
+"%PHP_COMMAND%" "%YII_PATH%init" %*
+
+@endlocal
diff --git a/requirements.php b/requirements.php
new file mode 100644
index 0000000..fd84f47
--- /dev/null
+++ b/requirements.php
@@ -0,0 +1,132 @@
+Error';
+ echo 'The path to yii framework seems to be incorrect.
';
+ echo 'You need to install Yii framework via composer or adjust the framework path in file ' . basename(__FILE__) . ' .
';
+ echo 'Please refer to the README on how to install Yii.
';
+}
+
+require_once($frameworkPath . '/requirements/YiiRequirementChecker.php');
+$requirementsChecker = new YiiRequirementChecker();
+
+$gdMemo = $imagickMemo = 'Either GD PHP extension with FreeType support or ImageMagick PHP extension with PNG support is required for image CAPTCHA.';
+$gdOK = $imagickOK = false;
+
+if (extension_loaded('imagick')) {
+ $imagick = new Imagick();
+ $imagickFormats = $imagick->queryFormats('PNG');
+ if (in_array('PNG', $imagickFormats)) {
+ $imagickOK = true;
+ } else {
+ $imagickMemo = 'Imagick extension should be installed with PNG support in order to be used for image CAPTCHA.';
+ }
+}
+
+if (extension_loaded('gd')) {
+ $gdInfo = gd_info();
+ if (!empty($gdInfo['FreeType Support'])) {
+ $gdOK = true;
+ } else {
+ $gdMemo = 'GD extension should be installed with FreeType support in order to be used for image CAPTCHA.';
+ }
+}
+
+/**
+ * Adjust requirements according to your application specifics.
+ */
+$requirements = array(
+ // Database :
+ array(
+ 'name' => 'PDO extension',
+ 'mandatory' => true,
+ 'condition' => extension_loaded('pdo'),
+ 'by' => 'All DB-related classes',
+ ),
+ array(
+ 'name' => 'PDO SQLite extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('pdo_sqlite'),
+ 'by' => 'All DB-related classes',
+ 'memo' => 'Required for SQLite database.',
+ ),
+ array(
+ 'name' => 'PDO MySQL extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('pdo_mysql'),
+ 'by' => 'All DB-related classes',
+ 'memo' => 'Required for MySQL database.',
+ ),
+ array(
+ 'name' => 'PDO PostgreSQL extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('pdo_pgsql'),
+ 'by' => 'All DB-related classes',
+ 'memo' => 'Required for PostgreSQL database.',
+ ),
+ // Cache :
+ array(
+ 'name' => 'Memcache extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('memcache') || extension_loaded('memcached'),
+ 'by' => 'MemCache ',
+ 'memo' => extension_loaded('memcached') ? 'To use memcached set MemCache::useMemcached to true
.' : ''
+ ),
+ array(
+ 'name' => 'APC extension',
+ 'mandatory' => false,
+ 'condition' => extension_loaded('apc'),
+ 'by' => 'ApcCache ',
+ ),
+ // CAPTCHA:
+ array(
+ 'name' => 'GD PHP extension with FreeType support',
+ 'mandatory' => false,
+ 'condition' => $gdOK,
+ 'by' => 'Captcha ',
+ 'memo' => $gdMemo,
+ ),
+ array(
+ 'name' => 'ImageMagick PHP extension with PNG support',
+ 'mandatory' => false,
+ 'condition' => $imagickOK,
+ 'by' => 'Captcha ',
+ 'memo' => $imagickMemo,
+ ),
+ // PHP ini :
+ 'phpExposePhp' => array(
+ 'name' => 'Expose PHP',
+ 'mandatory' => false,
+ 'condition' => $requirementsChecker->checkPhpIniOff("expose_php"),
+ 'by' => 'Security reasons',
+ 'memo' => '"expose_php" should be disabled at php.ini',
+ ),
+ 'phpAllowUrlInclude' => array(
+ 'name' => 'PHP allow url include',
+ 'mandatory' => false,
+ 'condition' => $requirementsChecker->checkPhpIniOff("allow_url_include"),
+ 'by' => 'Security reasons',
+ 'memo' => '"allow_url_include" should be disabled at php.ini',
+ ),
+ 'phpSmtp' => array(
+ 'name' => 'PHP mail SMTP',
+ 'mandatory' => false,
+ 'condition' => strlen(ini_get('SMTP')) > 0,
+ 'by' => 'Email sending',
+ 'memo' => 'PHP mail SMTP server required',
+ ),
+);
+$requirementsChecker->checkYii()->check($requirements)->render();
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..ad7f016
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,58 @@
+This directory contains various tests for the advanced applications.
+
+Tests in `codeception` directory are developed with [Codeception PHP Testing Framework](http://codeception.com/).
+
+After creating and setting up the advanced application, follow these steps to prepare for the tests:
+
+1. Install Codeception if it's not yet installed:
+
+ ```
+ composer global require "codeception/codeception=2.0.*" "codeception/specify=*" "codeception/verify=*"
+ ```
+
+ If you've never used Composer for global packages run `composer global status`. It should output:
+
+ ```
+ Changed current directory to
+ ```
+
+ Then add `/vendor/bin` to you `PATH` environment variable. Now you're able to use `codecept` from command
+ line globally.
+
+2. Install faker extension by running the following from template root directory where `composer.json` is:
+
+ ```
+ composer require --dev yiisoft/yii2-faker:*
+ ```
+
+3. Create `yii2_advanced_tests` database then update it by applying migrations:
+
+ ```
+ codeception/bin/yii migrate
+ ```
+
+4. In order to be able to run acceptance tests you need to start a webserver. The simplest way is to use PHP built in
+ webserver. In the root directory where `common`, `frontend` etc. are execute the following:
+
+ ```
+ php -S localhost:8080
+ ```
+
+5. Now you can run the tests with the following commands, assuming you are in the `tests/codeception` directory:
+
+ ```
+ # frontend tests
+ cd frontend
+ codecept build
+ codecept run
+
+ # backend tests
+
+ cd backend
+ codecept build
+ codecept run
+
+ # etc.
+ ```
+
+ If you already have run `codecept build` for each application, you can skip that step and run all tests by a single `codecept run`.
diff --git a/tests/codeception.yml b/tests/codeception.yml
new file mode 100644
index 0000000..1a793ed
--- /dev/null
+++ b/tests/codeception.yml
@@ -0,0 +1,11 @@
+include:
+ - codeception/common
+ - codeception/console
+ - codeception/backend
+ - codeception/frontend
+
+paths:
+ log: codeception/_output
+
+settings:
+ colors: true
diff --git a/tests/codeception/_output/.gitignore b/tests/codeception/_output/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/tests/codeception/_output/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/tests/codeception/backend/.gitignore b/tests/codeception/backend/.gitignore
new file mode 100644
index 0000000..985dbb4
--- /dev/null
+++ b/tests/codeception/backend/.gitignore
@@ -0,0 +1,4 @@
+# these files are auto generated by codeception build
+/unit/UnitTester.php
+/functional/FunctionalTester.php
+/acceptance/AcceptanceTester.php
diff --git a/tests/codeception/backend/_bootstrap.php b/tests/codeception/backend/_bootstrap.php
new file mode 100644
index 0000000..a28a3d2
--- /dev/null
+++ b/tests/codeception/backend/_bootstrap.php
@@ -0,0 +1,23 @@
+wantTo('ensure login page works');
+
+$loginPage = LoginPage::openBy($I);
+
+$I->amGoingTo('submit login form with no data');
+$loginPage->login('', '');
+if (method_exists($I, 'wait')) {
+ $I->wait(3); // only for selenium
+}
+$I->expectTo('see validations errors');
+$I->see('Username cannot be blank.', '.help-block');
+$I->see('Password cannot be blank.', '.help-block');
+
+$I->amGoingTo('try to login with wrong credentials');
+$I->expectTo('see validations errors');
+$loginPage->login('admin', 'wrong');
+if (method_exists($I, 'wait')) {
+ $I->wait(3); // only for selenium
+}
+$I->expectTo('see validations errors');
+$I->see('Incorrect username or password.', '.help-block');
+
+$I->amGoingTo('try to login with correct credentials');
+$loginPage->login('erau', 'password_0');
+if (method_exists($I, 'wait')) {
+ $I->wait(3); // only for selenium
+}
+$I->expectTo('see that user is logged');
+$I->seeLink('Logout (erau)');
+$I->dontSeeLink('Login');
+$I->dontSeeLink('Signup');
+/** Uncomment if using WebDriver
+ * $I->click('Logout (erau)');
+ * $I->dontSeeLink('Logout (erau)');
+ * $I->seeLink('Login');
+ */
diff --git a/tests/codeception/backend/acceptance/_bootstrap.php b/tests/codeception/backend/acceptance/_bootstrap.php
new file mode 100644
index 0000000..411855e
--- /dev/null
+++ b/tests/codeception/backend/acceptance/_bootstrap.php
@@ -0,0 +1,2 @@
+wantTo('ensure login page works');
+
+$loginPage = LoginPage::openBy($I);
+
+$I->amGoingTo('submit login form with no data');
+$loginPage->login('', '');
+$I->expectTo('see validations errors');
+$I->see('Username cannot be blank.', '.help-block');
+$I->see('Password cannot be blank.', '.help-block');
+
+$I->amGoingTo('try to login with wrong credentials');
+$I->expectTo('see validations errors');
+$loginPage->login('admin', 'wrong');
+$I->expectTo('see validations errors');
+$I->see('Incorrect username or password.', '.help-block');
+
+$I->amGoingTo('try to login with correct credentials');
+$loginPage->login('erau', 'password_0');
+$I->expectTo('see that user is logged');
+$I->seeLink('Logout (erau)');
+$I->dontSeeLink('Login');
+$I->dontSeeLink('Signup');
diff --git a/tests/codeception/backend/functional/_bootstrap.php b/tests/codeception/backend/functional/_bootstrap.php
new file mode 100644
index 0000000..94f3fbd
--- /dev/null
+++ b/tests/codeception/backend/functional/_bootstrap.php
@@ -0,0 +1,2 @@
+run();
+exit($exitCode);
diff --git a/tests/codeception/bin/yii.bat b/tests/codeception/bin/yii.bat
new file mode 100644
index 0000000..d516b3a
--- /dev/null
+++ b/tests/codeception/bin/yii.bat
@@ -0,0 +1,20 @@
+@echo off
+
+rem -------------------------------------------------------------
+rem Yii command line bootstrap script for Windows.
+rem
+rem @author Qiang Xue
+rem @link http://www.yiiframework.com/
+rem @copyright Copyright (c) 2008 Yii Software LLC
+rem @license http://www.yiiframework.com/license/
+rem -------------------------------------------------------------
+
+@setlocal
+
+set YII_PATH=%~dp0
+
+if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
+
+"%PHP_COMMAND%" "%YII_PATH%yii" %*
+
+@endlocal
diff --git a/tests/codeception/common/.gitignore b/tests/codeception/common/.gitignore
new file mode 100644
index 0000000..985dbb4
--- /dev/null
+++ b/tests/codeception/common/.gitignore
@@ -0,0 +1,4 @@
+# these files are auto generated by codeception build
+/unit/UnitTester.php
+/functional/FunctionalTester.php
+/acceptance/AcceptanceTester.php
diff --git a/tests/codeception/common/_bootstrap.php b/tests/codeception/common/_bootstrap.php
new file mode 100644
index 0000000..cea3ee5
--- /dev/null
+++ b/tests/codeception/common/_bootstrap.php
@@ -0,0 +1,15 @@
+actor->fillField('input[name="LoginForm[username]"]', $username);
+ $this->actor->fillField('input[name="LoginForm[password]"]', $password);
+ $this->actor->click('login-button');
+ }
+}
diff --git a/tests/codeception/common/_support/FixtureHelper.php b/tests/codeception/common/_support/FixtureHelper.php
new file mode 100644
index 0000000..c5ebcf1
--- /dev/null
+++ b/tests/codeception/common/_support/FixtureHelper.php
@@ -0,0 +1,72 @@
+loadFixtures();
+ }
+
+ /**
+ * Method is called after all suite tests run
+ */
+ public function _afterSuite()
+ {
+ $this->unloadFixtures();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function globalFixtures()
+ {
+ return [
+ InitDbFixture::className(),
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fixtures()
+ {
+ return [
+ 'user' => [
+ 'class' => UserFixture::className(),
+ 'dataFile' => '@tests/codeception/common/fixtures/data/init_login.php',
+ ],
+ ];
+ }
+}
diff --git a/tests/codeception/common/codeception.yml b/tests/codeception/common/codeception.yml
new file mode 100644
index 0000000..e8a3407
--- /dev/null
+++ b/tests/codeception/common/codeception.yml
@@ -0,0 +1,13 @@
+namespace: tests\codeception\common
+actor: Tester
+paths:
+ tests: .
+ log: _output
+ data: _data
+ helpers: _support
+settings:
+ bootstrap: _bootstrap.php
+ suite_class: \PHPUnit_Framework_TestSuite
+ colors: true
+ memory_limit: 1024M
+ log: true
diff --git a/tests/codeception/common/fixtures/UserFixture.php b/tests/codeception/common/fixtures/UserFixture.php
new file mode 100644
index 0000000..7153c8c
--- /dev/null
+++ b/tests/codeception/common/fixtures/UserFixture.php
@@ -0,0 +1,13 @@
+ 'erau',
+ 'auth_key' => 'tUu1qHcde0diwUol3xeI-18MuHkkprQI',
+ // password_0
+ 'password_hash' => '$2y$13$nJ1WDlBaGcbCdbNC5.5l4.sgy.OMEKCqtDQOdQ2OWpgiKRWYyzzne',
+ 'password_reset_token' => 'RkD_Jw0_8HEedzLk7MM-ZKEFfYR7VbMr_1392559490',
+ 'created_at' => '1392559490',
+ 'updated_at' => '1392559490',
+ 'email' => 'sfriesen@jenkins.info',
+ ],
+];
diff --git a/tests/codeception/common/templates/fixtures/user.php b/tests/codeception/common/templates/fixtures/user.php
new file mode 100644
index 0000000..d3f83b5
--- /dev/null
+++ b/tests/codeception/common/templates/fixtures/user.php
@@ -0,0 +1,17 @@
+getSecurity();
+
+return [
+ 'username' => $faker->userName,
+ 'email' => $faker->email,
+ 'auth_key' => $security->generateRandomString(),
+ 'password_hash' => $security->generatePasswordHash('password_' . $index),
+ 'password_reset_token' => $security->generateRandomString() . '_' . time(),
+ 'created_at' => time(),
+ 'updated_at' => time(),
+];
diff --git a/tests/codeception/common/unit.suite.yml b/tests/codeception/common/unit.suite.yml
new file mode 100644
index 0000000..a0582a5
--- /dev/null
+++ b/tests/codeception/common/unit.suite.yml
@@ -0,0 +1,6 @@
+# Codeception Test Suite Configuration
+
+# suite for unit (internal) tests.
+# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
+
+class_name: UnitTester
diff --git a/tests/codeception/common/unit/DbTestCase.php b/tests/codeception/common/unit/DbTestCase.php
new file mode 100644
index 0000000..2159a69
--- /dev/null
+++ b/tests/codeception/common/unit/DbTestCase.php
@@ -0,0 +1,11 @@
+ 'bayer.hudson',
+ 'auth_key' => 'HP187Mvq7Mmm3CTU80dLkGmni_FUH_lR',
+ //password_0
+ 'password_hash' => '$2y$13$EjaPFBnZOQsHdGuHI.xvhuDp1fHpo8hKRSk6yshqa9c5EG8s3C3lO',
+ 'password_reset_token' => 'ExzkCOaYc1L8IOBs4wdTGGbgNiG3Wz1I_1402312317',
+ 'created_at' => '1402312317',
+ 'updated_at' => '1402312317',
+ 'email' => 'nicole.paucek@schultz.info',
+ ],
+];
diff --git a/tests/codeception/common/unit/models/LoginFormTest.php b/tests/codeception/common/unit/models/LoginFormTest.php
new file mode 100644
index 0000000..54c8209
--- /dev/null
+++ b/tests/codeception/common/unit/models/LoginFormTest.php
@@ -0,0 +1,93 @@
+ [
+ 'user' => [
+ 'class' => 'yii\web\User',
+ 'identityClass' => 'common\models\User',
+ ],
+ ],
+ ]);
+ }
+
+ protected function tearDown()
+ {
+ Yii::$app->user->logout();
+ parent::tearDown();
+ }
+
+ public function testLoginNoUser()
+ {
+ $model = new LoginForm([
+ 'username' => 'not_existing_username',
+ 'password' => 'not_existing_password',
+ ]);
+
+ $this->specify('user should not be able to login, when there is no identity', function () use ($model) {
+ expect('model should not login user', $model->login())->false();
+ expect('user should not be logged in', Yii::$app->user->isGuest)->true();
+ });
+ }
+
+ public function testLoginWrongPassword()
+ {
+ $model = new LoginForm([
+ 'username' => 'bayer.hudson',
+ 'password' => 'wrong_password',
+ ]);
+
+ $this->specify('user should not be able to login with wrong password', function () use ($model) {
+ expect('model should not login user', $model->login())->false();
+ expect('error message should be set', $model->errors)->hasKey('password');
+ expect('user should not be logged in', Yii::$app->user->isGuest)->true();
+ });
+ }
+
+ public function testLoginCorrect()
+ {
+
+ $model = new LoginForm([
+ 'username' => 'bayer.hudson',
+ 'password' => 'password_0',
+ ]);
+
+ $this->specify('user should be able to login with correct credentials', function () use ($model) {
+ expect('model should login user', $model->login())->true();
+ expect('error message should not be set', $model->errors)->hasntKey('password');
+ expect('user should be logged in', Yii::$app->user->isGuest)->false();
+ });
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function fixtures()
+ {
+ return [
+ 'user' => [
+ 'class' => UserFixture::className(),
+ 'dataFile' => '@tests/codeception/common/unit/fixtures/data/models/user.php'
+ ],
+ ];
+ }
+}
diff --git a/tests/codeception/config/acceptance.php b/tests/codeception/config/acceptance.php
new file mode 100644
index 0000000..9318da5
--- /dev/null
+++ b/tests/codeception/config/acceptance.php
@@ -0,0 +1,7 @@
+ 'app-common',
+ 'basePath' => dirname(__DIR__),
+ ]
+);
diff --git a/tests/codeception/config/config.php b/tests/codeception/config/config.php
new file mode 100644
index 0000000..b478679
--- /dev/null
+++ b/tests/codeception/config/config.php
@@ -0,0 +1,26 @@
+ 'en-US',
+ 'controllerMap' => [
+ 'fixture' => [
+ 'class' => 'yii\faker\FixtureController',
+ 'fixtureDataPath' => '@tests/codeception/common/fixtures/data',
+ 'templatePath' => '@tests/codeception/common/templates/fixtures',
+ 'namespace' => 'tests\codeception\common\fixtures',
+ ],
+ ],
+ 'components' => [
+ 'db' => [
+ 'dsn' => 'mysql:host=localhost;dbname=yii2_advanced_tests',
+ ],
+ 'mailer' => [
+ 'useFileTransport' => true,
+ ],
+ 'urlManager' => [
+ 'showScriptName' => true,
+ ],
+ ],
+];
diff --git a/tests/codeception/config/console/unit.php b/tests/codeception/config/console/unit.php
new file mode 100644
index 0000000..4d3aeb0
--- /dev/null
+++ b/tests/codeception/config/console/unit.php
@@ -0,0 +1,14 @@
+ [
+ 'request' => [
+ // it's not recommended to run functional tests with CSRF validation enabled
+ 'enableCsrfValidation' => false,
+ // but if you absolutely need it set cookie domain to localhost
+ /*
+ 'csrfCookie' => [
+ 'domain' => 'localhost',
+ ],
+ */
+ ],
+ ],
+];
\ No newline at end of file
diff --git a/tests/codeception/config/unit.php b/tests/codeception/config/unit.php
new file mode 100644
index 0000000..6bd08d3
--- /dev/null
+++ b/tests/codeception/config/unit.php
@@ -0,0 +1,7 @@
+ $value) {
+ $inputType = $field === 'body' ? 'textarea' : 'input';
+ $this->actor->fillField($inputType . '[name="ContactForm[' . $field . ']"]', $value);
+ }
+ $this->actor->click('contact-button');
+ }
+}
diff --git a/tests/codeception/frontend/_pages/SignupPage.php b/tests/codeception/frontend/_pages/SignupPage.php
new file mode 100644
index 0000000..0e1cefa
--- /dev/null
+++ b/tests/codeception/frontend/_pages/SignupPage.php
@@ -0,0 +1,27 @@
+ $value) {
+ $inputType = $field === 'body' ? 'textarea' : 'input';
+ $this->actor->fillField($inputType . '[name="SignupForm[' . $field . ']"]', $value);
+ }
+ $this->actor->click('signup-button');
+ }
+}
diff --git a/tests/codeception/frontend/acceptance.suite.yml b/tests/codeception/frontend/acceptance.suite.yml
new file mode 100644
index 0000000..1828a04
--- /dev/null
+++ b/tests/codeception/frontend/acceptance.suite.yml
@@ -0,0 +1,28 @@
+# Codeception Test Suite Configuration
+
+# suite for acceptance tests.
+# perform tests in browser using the Selenium-like tools.
+# powered by Mink (http://mink.behat.org).
+# (tip: that's what your customer will see).
+# (tip: test your ajax and javascript by one of Mink drivers).
+
+# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
+
+class_name: AcceptanceTester
+modules:
+ enabled:
+ - PhpBrowser
+ - tests\codeception\common\_support\FixtureHelper
+# you can use WebDriver instead of PhpBrowser to test javascript and ajax.
+# This will require you to install selenium. See http://codeception.com/docs/04-AcceptanceTests#Selenium
+# "restart" option is used by the WebDriver to start each time per test-file new session and cookies,
+# it is useful if you want to login in your app in each test.
+# - WebDriver
+ config:
+ PhpBrowser:
+# PLEASE ADJUST IT TO THE ACTUAL ENTRY POINT WITHOUT PATH INFO
+ url: http://localhost:8080
+# WebDriver:
+# url: http://localhost:8080
+# browser: firefox
+# restart: true
diff --git a/tests/codeception/frontend/acceptance/AboutCept.php b/tests/codeception/frontend/acceptance/AboutCept.php
new file mode 100644
index 0000000..50bf9ba
--- /dev/null
+++ b/tests/codeception/frontend/acceptance/AboutCept.php
@@ -0,0 +1,10 @@
+wantTo('ensure that about works');
+AboutPage::openBy($I);
+$I->see('About', 'h1');
diff --git a/tests/codeception/frontend/acceptance/ContactCept.php b/tests/codeception/frontend/acceptance/ContactCept.php
new file mode 100644
index 0000000..f7a6bc8
--- /dev/null
+++ b/tests/codeception/frontend/acceptance/ContactCept.php
@@ -0,0 +1,56 @@
+wantTo('ensure that contact works');
+
+$contactPage = ContactPage::openBy($I);
+
+$I->see('Contact', 'h1');
+
+$I->amGoingTo('submit contact form with no data');
+$contactPage->submit([]);
+if (method_exists($I, 'wait')) {
+ $I->wait(3); // only for selenium
+}
+$I->expectTo('see validations errors');
+$I->see('Contact', 'h1');
+$I->see('Name cannot be blank', '.help-block');
+$I->see('Email cannot be blank', '.help-block');
+$I->see('Subject cannot be blank', '.help-block');
+$I->see('Body cannot be blank', '.help-block');
+$I->see('The verification code is incorrect', '.help-block');
+
+$I->amGoingTo('submit contact form with not correct email');
+$contactPage->submit([
+ 'name' => 'tester',
+ 'email' => 'tester.email',
+ 'subject' => 'test subject',
+ 'body' => 'test content',
+ 'verifyCode' => 'testme',
+]);
+if (method_exists($I, 'wait')) {
+ $I->wait(3); // only for selenium
+}
+$I->expectTo('see that email adress is wrong');
+$I->dontSee('Name cannot be blank', '.help-block');
+$I->see('Email is not a valid email address.', '.help-block');
+$I->dontSee('Subject cannot be blank', '.help-block');
+$I->dontSee('Body cannot be blank', '.help-block');
+$I->dontSee('The verification code is incorrect', '.help-block');
+
+$I->amGoingTo('submit contact form with correct data');
+$contactPage->submit([
+ 'name' => 'tester',
+ 'email' => 'tester@example.com',
+ 'subject' => 'test subject',
+ 'body' => 'test content',
+ 'verifyCode' => 'testme',
+]);
+if (method_exists($I, 'wait')) {
+ $I->wait(3); // only for selenium
+}
+$I->see('Thank you for contacting us. We will respond to you as soon as possible.');
diff --git a/tests/codeception/frontend/acceptance/HomeCept.php b/tests/codeception/frontend/acceptance/HomeCept.php
new file mode 100644
index 0000000..9566a2e
--- /dev/null
+++ b/tests/codeception/frontend/acceptance/HomeCept.php
@@ -0,0 +1,12 @@
+wantTo('ensure that home page works');
+$I->amOnPage(Yii::$app->homeUrl);
+$I->see('My Company');
+$I->seeLink('About');
+$I->click('About');
+$I->see('This is the About page.');
diff --git a/tests/codeception/frontend/acceptance/LoginCept.php b/tests/codeception/frontend/acceptance/LoginCept.php
new file mode 100644
index 0000000..599e24f
--- /dev/null
+++ b/tests/codeception/frontend/acceptance/LoginCept.php
@@ -0,0 +1,34 @@
+wantTo('ensure login page works');
+
+$loginPage = LoginPage::openBy($I);
+
+$I->amGoingTo('submit login form with no data');
+$loginPage->login('', '');
+$I->expectTo('see validations errors');
+$I->see('Username cannot be blank.', '.help-block');
+$I->see('Password cannot be blank.', '.help-block');
+
+$I->amGoingTo('try to login with wrong credentials');
+$I->expectTo('see validations errors');
+$loginPage->login('admin', 'wrong');
+$I->expectTo('see validations errors');
+$I->see('Incorrect username or password.', '.help-block');
+
+$I->amGoingTo('try to login with correct credentials');
+$loginPage->login('erau', 'password_0');
+$I->expectTo('see that user is logged');
+$I->seeLink('Logout (erau)');
+$I->dontSeeLink('Login');
+$I->dontSeeLink('Signup');
+/** Uncomment if using WebDriver
+ * $I->click('Logout (erau)');
+ * $I->dontSeeLink('Logout (erau)');
+ * $I->seeLink('Login');
+ */
diff --git a/tests/codeception/frontend/acceptance/SignupCest.php b/tests/codeception/frontend/acceptance/SignupCest.php
new file mode 100644
index 0000000..ab4b7bb
--- /dev/null
+++ b/tests/codeception/frontend/acceptance/SignupCest.php
@@ -0,0 +1,82 @@
+ 'tester.email@example.com',
+ 'username' => 'tester',
+ ]);
+ }
+
+ /**
+ * This method is called when test fails.
+ * @param \Codeception\Event\FailEvent $event
+ */
+ public function _fail($event)
+ {
+ }
+
+ /**
+ * @param \codeception_frontend\AcceptanceTester $I
+ * @param \Codeception\Scenario $scenario
+ */
+ public function testUserSignup($I, $scenario)
+ {
+ $I->wantTo('ensure that signup works');
+
+ $signupPage = SignupPage::openBy($I);
+ $I->see('Signup', 'h1');
+ $I->see('Please fill out the following fields to signup:');
+
+ $I->amGoingTo('submit signup form with no data');
+
+ $signupPage->submit([]);
+
+ $I->expectTo('see validation errors');
+ $I->see('Username cannot be blank.', '.help-block');
+ $I->see('Email cannot be blank.', '.help-block');
+ $I->see('Password cannot be blank.', '.help-block');
+
+ $I->amGoingTo('submit signup form with not correct email');
+ $signupPage->submit([
+ 'username' => 'tester',
+ 'email' => 'tester.email',
+ 'password' => 'tester_password',
+ ]);
+
+ $I->expectTo('see that email address is wrong');
+ $I->dontSee('Username cannot be blank.', '.help-block');
+ $I->dontSee('Password cannot be blank.', '.help-block');
+ $I->see('Email is not a valid email address.', '.help-block');
+
+ $I->amGoingTo('submit signup form with correct email');
+ $signupPage->submit([
+ 'username' => 'tester',
+ 'email' => 'tester.email@example.com',
+ 'password' => 'tester_password',
+ ]);
+
+ $I->expectTo('see that user logged in');
+ $I->seeLink('Logout (tester)');
+ }
+}
diff --git a/tests/codeception/frontend/acceptance/_bootstrap.php b/tests/codeception/frontend/acceptance/_bootstrap.php
new file mode 100644
index 0000000..b0a40ef
--- /dev/null
+++ b/tests/codeception/frontend/acceptance/_bootstrap.php
@@ -0,0 +1,2 @@
+wantTo('ensure that about works');
+AboutPage::openBy($I);
+$I->see('About', 'h1');
diff --git a/tests/codeception/frontend/functional/ContactCept.php b/tests/codeception/frontend/functional/ContactCept.php
new file mode 100644
index 0000000..c61d4c2
--- /dev/null
+++ b/tests/codeception/frontend/functional/ContactCept.php
@@ -0,0 +1,47 @@
+wantTo('ensure that contact works');
+
+$contactPage = ContactPage::openBy($I);
+
+$I->see('Contact', 'h1');
+
+$I->amGoingTo('submit contact form with no data');
+$contactPage->submit([]);
+$I->expectTo('see validations errors');
+$I->see('Contact', 'h1');
+$I->see('Name cannot be blank', '.help-block');
+$I->see('Email cannot be blank', '.help-block');
+$I->see('Subject cannot be blank', '.help-block');
+$I->see('Body cannot be blank', '.help-block');
+$I->see('The verification code is incorrect', '.help-block');
+
+$I->amGoingTo('submit contact form with not correct email');
+$contactPage->submit([
+ 'name' => 'tester',
+ 'email' => 'tester.email',
+ 'subject' => 'test subject',
+ 'body' => 'test content',
+ 'verifyCode' => 'testme',
+]);
+$I->expectTo('see that email adress is wrong');
+$I->dontSee('Name cannot be blank', '.help-block');
+$I->see('Email is not a valid email address.', '.help-block');
+$I->dontSee('Subject cannot be blank', '.help-block');
+$I->dontSee('Body cannot be blank', '.help-block');
+$I->dontSee('The verification code is incorrect', '.help-block');
+
+$I->amGoingTo('submit contact form with correct data');
+$contactPage->submit([
+ 'name' => 'tester',
+ 'email' => 'tester@example.com',
+ 'subject' => 'test subject',
+ 'body' => 'test content',
+ 'verifyCode' => 'testme',
+]);
+$I->see('Thank you for contacting us. We will respond to you as soon as possible.');
diff --git a/tests/codeception/frontend/functional/HomeCept.php b/tests/codeception/frontend/functional/HomeCept.php
new file mode 100644
index 0000000..f340061
--- /dev/null
+++ b/tests/codeception/frontend/functional/HomeCept.php
@@ -0,0 +1,12 @@
+wantTo('ensure that home page works');
+$I->amOnPage(Yii::$app->homeUrl);
+$I->see('My Company');
+$I->seeLink('About');
+$I->click('About');
+$I->see('This is the About page.');
diff --git a/tests/codeception/frontend/functional/LoginCept.php b/tests/codeception/frontend/functional/LoginCept.php
new file mode 100644
index 0000000..daca12c
--- /dev/null
+++ b/tests/codeception/frontend/functional/LoginCept.php
@@ -0,0 +1,29 @@
+wantTo('ensure login page works');
+
+$loginPage = LoginPage::openBy($I);
+
+$I->amGoingTo('submit login form with no data');
+$loginPage->login('', '');
+$I->expectTo('see validations errors');
+$I->see('Username cannot be blank.', '.help-block');
+$I->see('Password cannot be blank.', '.help-block');
+
+$I->amGoingTo('try to login with wrong credentials');
+$I->expectTo('see validations errors');
+$loginPage->login('admin', 'wrong');
+$I->expectTo('see validations errors');
+$I->see('Incorrect username or password.', '.help-block');
+
+$I->amGoingTo('try to login with correct credentials');
+$loginPage->login('erau', 'password_0');
+$I->expectTo('see that user is logged');
+$I->seeLink('Logout (erau)');
+$I->dontSeeLink('Login');
+$I->dontSeeLink('Signup');
diff --git a/tests/codeception/frontend/functional/SignupCest.php b/tests/codeception/frontend/functional/SignupCest.php
new file mode 100644
index 0000000..525b037
--- /dev/null
+++ b/tests/codeception/frontend/functional/SignupCest.php
@@ -0,0 +1,90 @@
+ 'tester.email@example.com',
+ 'username' => 'tester',
+ ]);
+ }
+
+ /**
+ * This method is called when test fails.
+ * @param \Codeception\Event\FailEvent $event
+ */
+ public function _fail($event)
+ {
+
+ }
+
+ /**
+ *
+ * @param \codeception_frontend\FunctionalTester $I
+ * @param \Codeception\Scenario $scenario
+ */
+ public function testUserSignup($I, $scenario)
+ {
+ $I->wantTo('ensure that signup works');
+
+ $signupPage = SignupPage::openBy($I);
+ $I->see('Signup', 'h1');
+ $I->see('Please fill out the following fields to signup:');
+
+ $I->amGoingTo('submit signup form with no data');
+
+ $signupPage->submit([]);
+
+ $I->expectTo('see validation errors');
+ $I->see('Username cannot be blank.', '.help-block');
+ $I->see('Email cannot be blank.', '.help-block');
+ $I->see('Password cannot be blank.', '.help-block');
+
+ $I->amGoingTo('submit signup form with not correct email');
+ $signupPage->submit([
+ 'username' => 'tester',
+ 'email' => 'tester.email',
+ 'password' => 'tester_password',
+ ]);
+
+ $I->expectTo('see that email address is wrong');
+ $I->dontSee('Username cannot be blank.', '.help-block');
+ $I->dontSee('Password cannot be blank.', '.help-block');
+ $I->see('Email is not a valid email address.', '.help-block');
+
+ $I->amGoingTo('submit signup form with correct email');
+ $signupPage->submit([
+ 'username' => 'tester',
+ 'email' => 'tester.email@example.com',
+ 'password' => 'tester_password',
+ ]);
+
+ $I->expectTo('see that user is created');
+ $I->seeRecord('common\models\User', [
+ 'username' => 'tester',
+ 'email' => 'tester.email@example.com',
+ ]);
+
+ $I->expectTo('see that user logged in');
+ $I->seeLink('Logout (tester)');
+ }
+}
diff --git a/tests/codeception/frontend/functional/_bootstrap.php b/tests/codeception/frontend/functional/_bootstrap.php
new file mode 100644
index 0000000..1abc491
--- /dev/null
+++ b/tests/codeception/frontend/functional/_bootstrap.php
@@ -0,0 +1,3 @@
+ 'okirlin',
+ 'auth_key' => 'iwTNae9t34OmnK6l4vT4IeaTk-YWI2Rv',
+ 'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi',
+ 'password_reset_token' => 't5GU9NwpuGYSfb7FEZMAxqtuz2PkEvv_' . time(),
+ 'created_at' => '1391885313',
+ 'updated_at' => '1391885313',
+ 'email' => 'brady.renner@rutherford.com',
+ ],
+ [
+ 'username' => 'troy.becker',
+ 'auth_key' => 'EdKfXrx88weFMV0vIxuTMWKgfK2tS3Lp',
+ 'password_hash' => '$2y$13$g5nv41Px7VBqhS3hVsVN2.MKfgT3jFdkXEsMC4rQJLfaMa7VaJqL2',
+ 'password_reset_token' => '4BSNyiZNAuxjs5Mty990c47sVrgllIi_' . time(),
+ 'created_at' => '1391885313',
+ 'updated_at' => '1391885313',
+ 'email' => 'nicolas.dianna@hotmail.com',
+ 'status' => '0',
+ ],
+];
diff --git a/tests/codeception/frontend/unit/models/ContactFormTest.php b/tests/codeception/frontend/unit/models/ContactFormTest.php
new file mode 100644
index 0000000..9aaf595
--- /dev/null
+++ b/tests/codeception/frontend/unit/models/ContactFormTest.php
@@ -0,0 +1,59 @@
+mailer->fileTransportCallback = function ($mailer, $message) {
+ return 'testing_message.eml';
+ };
+ }
+
+ protected function tearDown()
+ {
+ unlink($this->getMessageFile());
+ parent::tearDown();
+ }
+
+ public function testContact()
+ {
+ $model = new ContactForm();
+
+ $model->attributes = [
+ 'name' => 'Tester',
+ 'email' => 'tester@example.com',
+ 'subject' => 'very important letter subject',
+ 'body' => 'body of current message',
+ ];
+
+ $model->sendEmail('admin@example.com');
+
+ $this->specify('email should be send', function () {
+ expect('email file should exist', file_exists($this->getMessageFile()))->true();
+ });
+
+ $this->specify('message should contain correct data', function () use ($model) {
+ $emailMessage = file_get_contents($this->getMessageFile());
+
+ expect('email should contain user name', $emailMessage)->contains($model->name);
+ expect('email should contain sender email', $emailMessage)->contains($model->email);
+ expect('email should contain subject', $emailMessage)->contains($model->subject);
+ expect('email should contain body', $emailMessage)->contains($model->body);
+ });
+ }
+
+ private function getMessageFile()
+ {
+ return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';
+ }
+}
diff --git a/tests/codeception/frontend/unit/models/PasswordResetRequestFormTest.php b/tests/codeception/frontend/unit/models/PasswordResetRequestFormTest.php
new file mode 100644
index 0000000..ced8cce
--- /dev/null
+++ b/tests/codeception/frontend/unit/models/PasswordResetRequestFormTest.php
@@ -0,0 +1,87 @@
+mailer->fileTransportCallback = function ($mailer, $message) {
+ return 'testing_message.eml';
+ };
+ }
+
+ protected function tearDown()
+ {
+ @unlink($this->getMessageFile());
+
+ parent::tearDown();
+ }
+
+ public function testSendEmailWrongUser()
+ {
+ $this->specify('no user with such email, message should not be sent', function () {
+
+ $model = new PasswordResetRequestForm();
+ $model->email = 'not-existing-email@example.com';
+
+ expect('email not sent', $model->sendEmail())->false();
+
+ });
+
+ $this->specify('user is not active, message should not be sent', function () {
+
+ $model = new PasswordResetRequestForm();
+ $model->email = $this->user[1]['email'];
+
+ expect('email not sent', $model->sendEmail())->false();
+
+ });
+ }
+
+ public function testSendEmailCorrectUser()
+ {
+ $model = new PasswordResetRequestForm();
+ $model->email = $this->user[0]['email'];
+ $user = User::findOne(['password_reset_token' => $this->user[0]['password_reset_token']]);
+
+ expect('email sent', $model->sendEmail())->true();
+ expect('user has valid token', $user->password_reset_token)->notNull();
+
+ $this->specify('message has correct format', function () use ($model) {
+
+ expect('message file exists', file_exists($this->getMessageFile()))->true();
+
+ $message = file_get_contents($this->getMessageFile());
+ expect('message "from" is correct', $message)->contains(Yii::$app->params['supportEmail']);
+ expect('message "to" is correct', $message)->contains($model->email);
+
+ });
+ }
+
+ public function fixtures()
+ {
+ return [
+ 'user' => [
+ 'class' => UserFixture::className(),
+ 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'
+ ],
+ ];
+ }
+
+ private function getMessageFile()
+ {
+ return Yii::getAlias(Yii::$app->mailer->fileTransportPath) . '/testing_message.eml';
+ }
+}
diff --git a/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php b/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php
new file mode 100644
index 0000000..a4dd021
--- /dev/null
+++ b/tests/codeception/frontend/unit/models/ResetPasswordFormTest.php
@@ -0,0 +1,43 @@
+user[0]['password_reset_token']);
+ expect('password should be resetted', $form->resetPassword())->true();
+ }
+
+ public function fixtures()
+ {
+ return [
+ 'user' => [
+ 'class' => UserFixture::className(),
+ 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php'
+ ],
+ ];
+ }
+}
diff --git a/tests/codeception/frontend/unit/models/SignupFormTest.php b/tests/codeception/frontend/unit/models/SignupFormTest.php
new file mode 100644
index 0000000..4d08e8c
--- /dev/null
+++ b/tests/codeception/frontend/unit/models/SignupFormTest.php
@@ -0,0 +1,52 @@
+ 'some_username',
+ 'email' => 'some_email@example.com',
+ 'password' => 'some_password',
+ ]);
+
+ $user = $model->signup();
+
+ $this->assertInstanceOf('common\models\User', $user, 'user should be valid');
+
+ expect('username should be correct', $user->username)->equals('some_username');
+ expect('email should be correct', $user->email)->equals('some_email@example.com');
+ expect('password should be correct', $user->validatePassword('some_password'))->true();
+ }
+
+ public function testNotCorrectSignup()
+ {
+ $model = new SignupForm([
+ 'username' => 'troy.becker',
+ 'email' => 'nicolas.dianna@hotmail.com',
+ 'password' => 'some_password',
+ ]);
+
+ expect('username and email are in use, user should not be created', $model->signup())->null();
+ }
+
+ public function fixtures()
+ {
+ return [
+ 'user' => [
+ 'class' => UserFixture::className(),
+ 'dataFile' => '@tests/codeception/frontend/unit/fixtures/data/models/user.php',
+ ],
+ ];
+ }
+}
diff --git a/yii b/yii
new file mode 100644
index 0000000..6f0c6d2
--- /dev/null
+++ b/yii
@@ -0,0 +1,28 @@
+#!/usr/bin/env php
+run();
+exit($exitCode);
diff --git a/yii.bat b/yii.bat
new file mode 100644
index 0000000..d516b3a
--- /dev/null
+++ b/yii.bat
@@ -0,0 +1,20 @@
+@echo off
+
+rem -------------------------------------------------------------
+rem Yii command line bootstrap script for Windows.
+rem
+rem @author Qiang Xue
+rem @link http://www.yiiframework.com/
+rem @copyright Copyright (c) 2008 Yii Software LLC
+rem @license http://www.yiiframework.com/license/
+rem -------------------------------------------------------------
+
+@setlocal
+
+set YII_PATH=%~dp0
+
+if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe
+
+"%PHP_COMMAND%" "%YII_PATH%yii" %*
+
+@endlocal
--
libgit2 0.21.4