first commit

This commit is contained in:
Денис Хорош 2023-05-06 20:40:02 +03:00
commit fdf3e1e602
221 changed files with 12262 additions and 0 deletions

3
.bowerrc Executable file
View File

@ -0,0 +1,3 @@
{
"directory" : "vendor/bower-asset"
}

43
.gitignore vendored Executable file
View File

@ -0,0 +1,43 @@
# yii console commands
/yii
/yii_test
/yii_test.bat
# phpstorm project files
.idea
# netbeans project files
nbproject
# zend studio for eclipse project files
.buildpath
.project
.settings
# windows thumbnail cache
Thumbs.db
# composer vendor dir
/vendor
# composer itself is not needed
composer.phar
# Mac DS_Store Files
.DS_Store
# phpunit itself is not needed
phpunit.phar
# local phpunit config
/phpunit.xml
# vagrant runtime
/.vagrant
# ignore generated files
/frontend/web/index.php
/frontend/web/index-test.php
/frontend/web/robots.txt
/backend/web/index.php
/backend/web/index-test.php
/backend/web/robots.txt

29
LICENSE.md Executable file
View File

@ -0,0 +1,29 @@
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.

60
README.md Executable file
View File

@ -0,0 +1,60 @@
<p align="center">
<a href="https://github.com/yiisoft" target="_blank">
<img src="https://avatars0.githubusercontent.com/u/993323" height="100px">
</a>
<h1 align="center">Yii 2 Advanced Project Template</h1>
<br>
</p>
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).
[![Latest Stable Version](https://img.shields.io/packagist/v/yiisoft/yii2-app-advanced.svg)](https://packagist.org/packages/yiisoft/yii2-app-advanced)
[![Total Downloads](https://img.shields.io/packagist/dt/yiisoft/yii2-app-advanced.svg)](https://packagist.org/packages/yiisoft/yii2-app-advanced)
[![build](https://github.com/yiisoft/yii2-app-advanced/workflows/build/badge.svg)](https://github.com/yiisoft/yii2-app-advanced/actions?query=workflow%3Abuild)
DIRECTORY STRUCTURE
-------------------
```
common
config/ contains shared configurations
mail/ contains view files for e-mails
models/ contains model classes used in both backend and frontend
tests/ contains tests for common classes
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
tests/ contains tests for backend application
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
tests/ contains tests for frontend application
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
```

88
Vagrantfile vendored Executable file
View File

@ -0,0 +1,88 @@
require 'yaml'
require 'fileutils'
required_plugins_installed = nil
required_plugins = %w( vagrant-hostmanager vagrant-vbguest )
required_plugins.each do |plugin|
unless Vagrant.has_plugin? plugin
system "vagrant plugin install #{plugin}"
required_plugins_installed = true
end
end
# IF plugin[s] was just installed - restart required
if required_plugins_installed
# Get CLI command[s] and call again
system 'vagrant' + ARGV.to_s.gsub(/\[\"|\", \"|\"\]/, ' ')
exit
end
domains = {
frontend: 'y2aa-frontend.test',
backend: 'y2aa-backend.test'
}
config = {
local: './vagrant/config/vagrant-local.yml',
example: './vagrant/config/vagrant-local.example.yml'
}
# copy config from example if local config not exists
FileUtils.cp config[:example], config[:local] unless File.exist?(config[:local])
# read config
options = YAML.load_file config[:local]
# check github token
if options['github_token'].nil? || options['github_token'].to_s.length != 40
puts "You must place REAL GitHub token into configuration:\n/yii2-app-advanced/vagrant/config/vagrant-local.yml"
exit
end
# vagrant configurate
Vagrant.configure(2) do |config|
# select the box
config.vm.box = 'bento/ubuntu-18.04'
# should we ask about box updates?
config.vm.box_check_update = options['box_check_update']
config.vm.provider 'virtualbox' do |vb|
# machine cpus count
vb.cpus = options['cpus']
# machine memory size
vb.memory = options['memory']
# machine name (for VirtualBox UI)
vb.name = options['machine_name']
end
# machine name (for vagrant console)
config.vm.define options['machine_name']
# machine name (for guest machine console)
config.vm.hostname = options['machine_name']
# network settings
config.vm.network 'private_network', ip: options['ip']
# sync: folder 'yii2-app-advanced' (host machine) -> folder '/app' (guest machine)
config.vm.synced_folder './', '/app', owner: 'vagrant', group: 'vagrant'
# disable folder '/vagrant' (guest machine)
config.vm.synced_folder '.', '/vagrant', disabled: true
# hosts settings (host machine)
config.vm.provision :hostmanager
config.hostmanager.enabled = true
config.hostmanager.manage_host = true
config.hostmanager.ignore_private_ip = false
config.hostmanager.include_offline = true
config.hostmanager.aliases = domains.values
# provisioners
config.vm.provision 'shell', path: './vagrant/provision/once-as-root.sh', args: [options['timezone'], options['ip']]
config.vm.provision 'shell', path: './vagrant/provision/once-as-vagrant.sh', args: [options['github_token']], privileged: false
config.vm.provision 'shell', path: './vagrant/provision/always-as-root.sh', run: 'always'
# post-install message (vagrant console)
config.vm.post_up_message = "Frontend URL: http://#{domains[:frontend]}\nBackend URL: http://#{domains[:backend]}"
end

4
backend/Dockerfile Executable file
View File

@ -0,0 +1,4 @@
FROM yiisoftware/yii2-php:8.1-apache
# Change document root for Apache
RUN sed -i -e 's|/app/web|/app/backend/web|g' /etc/apache2/sites-available/000-default.conf

23
backend/assets/AppAsset.php Executable file
View File

@ -0,0 +1,23 @@
<?php
namespace backend\assets;
use yii\web\AssetBundle;
/**
* Main backend application asset bundle.
*/
class AppAsset extends AssetBundle
{
public $basePath = '@webroot';
public $baseUrl = '@web';
public $css = [
'css/site.css',
];
public $js = [
];
public $depends = [
'yii\web\YiiAsset',
'yii\bootstrap5\BootstrapAsset',
];
}

15
backend/codeception.yml Executable file
View File

@ -0,0 +1,15 @@
namespace: backend\tests
actor_suffix: Tester
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
bootstrap: _bootstrap.php
settings:
colors: true
memory_limit: 1024M
modules:
config:
Yii2:
configFile: 'config/codeception-local.php'

4
backend/config/.gitignore vendored Executable file
View File

@ -0,0 +1,4 @@
codeception-local.php
main-local.php
params-local.php
test-local.php

1
backend/config/bootstrap.php Executable file
View File

@ -0,0 +1 @@
<?php

58
backend/config/main.php Executable file
View File

@ -0,0 +1,58 @@
<?php
$params = array_merge(
require __DIR__ . '/../../common/config/params.php',
require __DIR__ . '/../../common/config/params-local.php',
require __DIR__ . '/params.php',
require __DIR__ . '/params-local.php'
);
return [
'homeUrl' => '/secure',
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'bootstrap' => ['log'],
'modules' => [
'news' => [
'class' => 'backend\modules\news\News',
],
'profile' => [
'class' => 'app\modules\profile\Profile',
],
],
'components' => [
'request' => [
'csrfParam' => '_csrf-backend',
'baseUrl' => '/secure',
],
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
],
'session' => [
// this is the name of the session cookie used for login on the backend
'name' => 'advanced-backend',
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => \yii\log\FileTarget::class,
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
],
'params' => $params,
];

4
backend/config/params.php Executable file
View File

@ -0,0 +1,4 @@
<?php
return [
'adminEmail' => 'admin@example.com',
];

15
backend/config/test.php Executable file
View File

@ -0,0 +1,15 @@
<?php
return [
'id' => 'app-backend-tests',
'components' => [
'assetManager' => [
'basePath' => __DIR__ . '/../web/assets',
],
'urlManager' => [
'showScriptName' => true,
],
'request' => [
'cookieValidationKey' => 'test',
],
],
];

View File

@ -0,0 +1,105 @@
<?php
namespace backend\controllers;
use common\models\LoginForm;
use Yii;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\web\Response;
use function PHPUnit\Framework\directoryExists;
/**
* Site controller
*/
class SiteController extends Controller
{
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'actions' => ['logout', 'index'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::class,
'actions' => [
'logout' => ['post'],
],
],
];
}
/**
* {@inheritdoc}
*/
public function actions()
{
return [
'error' => [
'class' => \yii\web\ErrorAction::class,
],
];
}
/**
* Displays homepage.
*
* @return string
*/
public function actionIndex()
{
return $this->render('index');
}
/**
* Login action.
*
* @return string|Response
*/
public function actionLogin()
{
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$this->layout = 'blank';
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
}
$model->password = '';
return $this->render('login', [
'model' => $model,
]);
}
/**
* Logout action.
*
* @return Response
*/
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
}

1
backend/models/.gitkeep Executable file
View File

@ -0,0 +1 @@
*

24
backend/modules/news/News.php Executable file
View File

@ -0,0 +1,24 @@
<?php
namespace backend\modules\news;
/**
* news module definition class
*/
class News extends \yii\base\Module
{
/**
* {@inheritdoc}
*/
public $controllerNamespace = 'app\modules\news\controllers';
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
// custom initialization code goes here
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace app\modules\news\controllers;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\web\Controller;
/**
* Default controller for the `news` module
*/
class DefaultController extends Controller
{
/**
* @inheritDoc
*/
public function behaviors()
{
return array_merge(
parent::behaviors(),
[
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'actions' => ['logout', 'index'],
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
]
);
}
/**
* Renders the index view for the module
* @return string
*/
public function actionIndex()
{
return $this->render('index');
}
}

View File

@ -0,0 +1,148 @@
<?php
namespace app\modules\news\controllers;
use common\models\News;
use app\modules\news\models\NewsSearch;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
/**
* NewsController implements the CRUD actions for News model.
*/
class NewsController extends Controller
{
/**
* @inheritDoc
*/
public function behaviors()
{
return array_merge(
parent::behaviors(),
[
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'allow' => true,
'roles' => ['@'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
]
);
}
/**
* Lists all News models.
*
* @return string
*/
public function actionIndex()
{
$searchModel = new NewsSearch();
$dataProvider = $searchModel->search($this->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
/**
* Displays a single News model.
* @param int $id ID
* @return string
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionView($id)
{
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
/**
* Creates a new News model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return string|\yii\web\Response
*/
public function actionCreate()
{
$model = new News();
if ($this->request->isPost) {
if ($model->load($this->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
} else {
$model->loadDefaultValues();
}
return $this->render('create', [
'model' => $model,
]);
}
/**
* Updates an existing News model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param int $id ID
* @return string|\yii\web\Response
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('update', [
'model' => $model,
]);
}
/**
* Deletes an existing News model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* @param int $id ID
* @return \yii\web\Response
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionDelete($id)
{
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
/**
* Finds the News model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param int $id ID
* @return News the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = News::findOne(['id' => $id])) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
}

View File

@ -0,0 +1,70 @@
<?php
namespace app\modules\news\models;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use common\models\News;
/**
* NewsSearch represents the model behind the search form of `common\models\News`.
*/
class NewsSearch extends News
{
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['id'], 'integer'],
[['title', 'text', 'slug'], 'safe'],
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* @param array $params
*
* @return ActiveDataProvider
*/
public function search($params)
{
$query = News::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
]);
$query->andFilterWhere(['like', 'title', $this->title])
->andFilterWhere(['like', 'text', $this->text])
->andFilterWhere(['like', 'slug', $this->slug]);
return $dataProvider;
}
}

View File

@ -0,0 +1,12 @@
<div class="news-default-index">
<h1><?= $this->context->action->uniqueId ?></h1>
<p>
This is the view content for action "<?= $this->context->action->id ?>".
The action belongs to the controller "<?= get_class($this->context) ?>"
in the "<?= $this->context->module->id ?>" module.
</p>
<p>
You may customize this page by editing the following file:<br>
<code><?= __FILE__ ?></code>
</p>
</div>

View File

@ -0,0 +1,31 @@
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/** @var yii\web\View $this */
/** @var common\models\News[] $model */
/** @var yii\widgets\ActiveForm $form */
?>
<div class="news-form">
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'title')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'text')->widget(\asmoday74\ckeditor5\EditorClassic::class, [
'clientOptions' => [
'language' => 'en',
]
]) ?>
<?= $form->field($model, 'slug')->textInput(['maxlength' => true]) ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>

View File

@ -0,0 +1,33 @@
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/** @var yii\web\View $this */
/** @var app\modules\news\models\NewsSearch $model */
/** @var yii\widgets\ActiveForm $form */
?>
<div class="news-search">
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'id') ?>
<?= $form->field($model, 'title') ?>
<?= $form->field($model, 'text') ?>
<?= $form->field($model, 'slug') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::resetButton('Reset', ['class' => 'btn btn-outline-secondary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>

View File

@ -0,0 +1,20 @@
<?php
use yii\helpers\Html;
/** @var yii\web\View $this */
/** @var common\models\News $model */
$this->title = 'Create News';
$this->params['breadcrumbs'][] = ['label' => 'News', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="news-create">
<h1><?= Html::encode($this->title) ?></h1>
<?= $this->render('_form', [
'model' => $model,
]) ?>
</div>

View File

@ -0,0 +1,46 @@
<?php
use common\models\News;
use yii\helpers\Html;
use yii\helpers\Url;
use yii\grid\ActionColumn;
use yii\grid\GridView;
/** @var yii\web\View $this */
/** @var app\modules\news\models\NewsSearch $searchModel */
/** @var yii\data\ActiveDataProvider $dataProvider */
$this->title = 'News';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="news-index">
<h1><?= Html::encode($this->title) ?></h1>
<p>
<?= Html::a('Create News', ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'title',
'text:ntext',
'slug',
[
'class' => ActionColumn::className(),
'urlCreator' => function ($action, News $model, $key, $index, $column) {
return Url::toRoute([$action, 'id' => $model->id]);
}
],
],
]); ?>
</div>

View File

@ -0,0 +1,21 @@
<?php
use yii\helpers\Html;
/** @var yii\web\View $this */
/** @var common\models\News $model */
$this->title = 'Update News: ' . $model->title;
$this->params['breadcrumbs'][] = ['label' => 'News', 'url' => ['index']];
$this->params['breadcrumbs'][] = ['label' => $model->title, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = 'Update';
?>
<div class="news-update">
<h1><?= Html::encode($this->title) ?></h1>
<?= $this->render('_form', [
'model' => $model,
]) ?>
</div>

View File

@ -0,0 +1,39 @@
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
/** @var yii\web\View $this */
/** @var common\models\News $model */
$this->title = $model->title;
$this->params['breadcrumbs'][] = ['label' => 'News', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
\yii\web\YiiAsset::register($this);
?>
<div class="news-view">
<h1><?= Html::encode($this->title) ?></h1>
<p>
<?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
<?= Html::a('Delete', ['delete', 'id' => $model->id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => 'Are you sure you want to delete this item?',
'method' => 'post',
],
]) ?>
</p>
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
'title',
'text:ntext',
'slug',
],
]) ?>
</div>

View File

@ -0,0 +1,24 @@
<?php
namespace app\modules\profile;
/**
* profile module definition class
*/
class Profile extends \yii\base\Module
{
/**
* {@inheritdoc}
*/
public $controllerNamespace = 'app\modules\profile\controllers';
/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
// custom initialization code goes here
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace app\modules\profile\controllers;
use yii\web\Controller;
/**
* Default controller for the `profile` module
*/
class DefaultController extends Controller
{
/**
* Renders the index view for the module
* @return string
*/
public function actionIndex()
{
return $this->render('index');
}
}

View File

@ -0,0 +1,166 @@
<?php
namespace app\modules\profile\controllers;
use app\modules\profile\models\ProfileSearch;
use common\models\Profile;
use common\services\UserService;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
/**
* ProfileController implements the CRUD actions for Profile model.
*/
class ProfileController extends Controller
{
/**
* @inheritDoc
*/
public function behaviors()
{
return array_merge(
parent::behaviors(),
[
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'actions' => ['login', 'error'],
'allow' => true,
],
[
'allow' => true,
'roles' => ['@'],
],
],
],
]
);
}
/**
* Lists all Profile models.
*
* @return string
*/
public function actionIndex()
{
$searchModel = new ProfileSearch();
$dataProvider = $searchModel->search($this->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]);
}
/**
* Displays a single Profile model.
* @param int $id ID
* @return string
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionView($id)
{
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
/**
* Creates a new Profile model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return string|\yii\web\Response
*/
public function actionCreate()
{
$model = new Profile();
$service = UserService::run();
$texts = $service->newTexts();
$users = $service->getAllUsers();
if ($this->request->isPost) {
if ($service->saveProfile($this->request->post(), $model)) {
$service->saveTexts($this->request->post('Text'), $model->id, $texts);
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('create', [
'model' => $model,
'users' => $users,
'texts' => $texts
]);
}
/**
* Updates an existing Profile model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param int $id ID
* @return string|\yii\web\Response
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);
$service = UserService::run();
$texts = $service->getTexts($id);
$users = $service->getAllUsers();
if ($this->request->isPost) {
if ($service->saveProfile($this->request->post(), $model)) {
$service->saveTexts($this->request->post('Text'), $model->id, $texts);
return $this->redirect(['view', 'id' => $model->id]);
}
}
return $this->render('update', [
'model' => $model,
'users' => $users,
'texts' => $texts
]);
}
/**
* Deletes an existing Profile model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* @param int $id ID
* @return \yii\web\Response
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionDelete($id)
{
$model = $this->findModel($id);
foreach ($model->texts as $text) {
$text->delete();
}
$model->delete();
return $this->redirect(['index']);
}
/**
* Finds the Profile model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param int $id ID
* @return Profile the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = Profile::findOne(['id' => $id])) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace app\modules\profile\models;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use common\models\Profile;
/**
* ProfileSearch represents the model behind the search form of `common\models\Profile`.
*/
class ProfileSearch extends Profile
{
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['id', 'user_id', 'activity'], 'integer'],
[['created_at', 'image'], 'safe'],
];
}
/**
* {@inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* @param array $params
*
* @return ActiveDataProvider
*/
public function search($params)
{
$query = Profile::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'id' => $this->id,
'user_id' => $this->user_id,
'created_at' => $this->created_at,
'activity' => $this->activity,
]);
$query->andFilterWhere(['like', 'image', $this->image]);
return $dataProvider;
}
}

View File

@ -0,0 +1,12 @@
<div class="profile-default-index">
<h1><?= $this->context->action->uniqueId ?></h1>
<p>
This is the view content for action "<?= $this->context->action->id ?>".
The action belongs to the controller "<?= get_class($this->context) ?>"
in the "<?= $this->context->module->id ?>" module.
</p>
<p>
You may customize this page by editing the following file:<br>
<code><?= __FILE__ ?></code>
</p>
</div>

View File

@ -0,0 +1,40 @@
<?php
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/** @var yii\web\View $this */
/** @var common\models\Profile $model */
/** @var common\models\User[] $users */
/** @var common\models\Text[] $texts */
/** @var yii\widgets\ActiveForm $form */
?>
<div class="profile-form">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($model, 'user_id')->dropDownList(ArrayHelper::map($users, 'id', 'username')) ?>
<?= $form->field($model, 'file')->fileInput() ?>
<?= $form->field($model, 'activity')->checkbox() ?>
<?php
if (!empty($texts)):
foreach ($texts as $i => $text): ?>
<?= $form->field($text, 'title[' . $text['language'] . ']')->textInput(['maxlength' => true, 'value' => $text->title])->label($text['language'] . ' заголовок') ?>
<?= $form->field($text, 'text[' . $text['language'] . ']')->textarea(['value' => $text->title])->label($text['language'] . ' текст') ?>
<?php endforeach; endif; ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>

View File

@ -0,0 +1,35 @@
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/** @var yii\web\View $this */
/** @var app\modules\profile\models\ProfileSearch $model */
/** @var yii\widgets\ActiveForm $form */
?>
<div class="profile-search">
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'id') ?>
<?= $form->field($model, 'user_id') ?>
<?= $form->field($model, 'created_at') ?>
<?= $form->field($model, 'image') ?>
<?= $form->field($model, 'activity') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::resetButton('Reset', ['class' => 'btn btn-outline-secondary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>

View File

@ -0,0 +1,24 @@
<?php
use yii\helpers\Html;
/** @var yii\web\View $this */
/** @var common\models\Profile $model */
/** @var common\models\User[] $users */
/** @var common\models\Text[] $texts */
$this->title = 'Create Profile';
$this->params['breadcrumbs'][] = ['label' => 'Profiles', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="profile-create">
<h1><?= Html::encode($this->title) ?></h1>
<?= $this->render('_form', [
'model' => $model,
'users' => $users,
'texts' => $texts
]) ?>
</div>

View File

@ -0,0 +1,57 @@
<?php
use common\models\Profile;
use yii\helpers\Html;
use yii\helpers\Url;
use yii\grid\ActionColumn;
use yii\grid\GridView;
/** @var yii\web\View $this */
/** @var app\modules\profile\models\ProfileSearch $searchModel */
/** @var yii\data\ActiveDataProvider $dataProvider */
$this->title = 'Profiles';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="profile-index">
<h1><?= Html::encode($this->title) ?></h1>
<p>
<?= Html::a('Create Profile', ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'created_at',
[
'attribute' => 'user_id',
'value' => function($model){return $model->user->username;},
],
[
'attribute' => 'image',
'value' => function($model){return '/uploads/' . $model->image;},
'format' => ['image', ['width' => 100, 'height' => 100]],
],
[
'attribute' => 'activity',
'value' => function($model){return $model->getStatusLabel();},
],
[
'class' => ActionColumn::className(),
'urlCreator' => function ($action, Profile $model, $key, $index, $column) {
return Url::toRoute([$action, 'id' => $model->id]);
}
],
],
]); ?>
</div>

View File

@ -0,0 +1,25 @@
<?php
use yii\helpers\Html;
/** @var yii\web\View $this */
/** @var common\models\Profile $model */
/** @var common\models\User[] $users */
/** @var common\models\Text[] $texts */
$this->title = 'Update Profile: ' . $model->id;
$this->params['breadcrumbs'][] = ['label' => 'Profiles', 'url' => ['index']];
$this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = 'Update';
?>
<div class="profile-update">
<h1><?= Html::encode($this->title) ?></h1>
<?= $this->render('_form', [
'model' => $model,
'users' => $users,
'texts' => $texts
]) ?>
</div>

View File

@ -0,0 +1,50 @@
<?php
use yii\helpers\Html;
use yii\widgets\DetailView;
/** @var yii\web\View $this */
/** @var common\models\Profile $model */
$this->title = $model->id;
$this->params['breadcrumbs'][] = ['label' => 'Profiles', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
\yii\web\YiiAsset::register($this);
?>
<div class="profile-view">
<h1><?= Html::encode($this->title) ?></h1>
<p>
<?= Html::a('Update', ['update', 'id' => $model->id], ['class' => 'btn btn-primary']) ?>
<?= Html::a('Delete', ['delete', 'id' => $model->id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => 'Are you sure you want to delete this item?',
'method' => 'post',
],
]) ?>
</p>
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
[
'attribute' => 'user_id',
'value' => function($model){return $model->user->username;},
],
'created_at',
[
'attribute' => 'image',
'value' => function($model){return '/uploads/' . $model->image;},
'format' => ['image', ['width' => 100, 'height' => 100]],
],
[
'attribute' => 'activity',
'value' => function($model){return $model->getStatusLabel();},
],
],
]) ?>
</div>

2
backend/runtime/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

10
backend/tests/_bootstrap.php Executable file
View File

@ -0,0 +1,10 @@
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
defined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', __DIR__.'/../../');
require_once YII_APP_BASE_PATH . '/vendor/autoload.php';
require_once YII_APP_BASE_PATH . '/vendor/yiisoft/yii2/Yii.php';
require_once YII_APP_BASE_PATH . '/common/config/bootstrap.php';
require_once __DIR__ . '/../config/bootstrap.php';

0
backend/tests/_data/.gitignore vendored Executable file
View File

View File

@ -0,0 +1,13 @@
<?php
return [
[
'username' => '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',
],
];

2
backend/tests/_output/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

1
backend/tests/_support/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
_generated

View File

@ -0,0 +1,26 @@
<?php
namespace backend\tests;
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void verify($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class FunctionalTester extends \Codeception\Actor
{
use _generated\FunctionalTesterActions;
/**
* Define custom actions here
*/
}

View File

@ -0,0 +1,26 @@
<?php
namespace backend\tests;
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void verify($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}

View File

@ -0,0 +1,5 @@
suite_namespace: backend\tests\functional
actor: FunctionalTester
modules:
enabled:
- Yii2

View File

@ -0,0 +1,44 @@
<?php
namespace backend\tests\functional;
use backend\tests\FunctionalTester;
use common\fixtures\UserFixture;
/**
* Class LoginCest
*/
class LoginCest
{
/**
* Load fixtures before db transaction begin
* Called in _before()
* @see \Codeception\Module\Yii2::_before()
* @see \Codeception\Module\Yii2::loadFixtures()
* @return array
*/
public function _fixtures()
{
return [
'user' => [
'class' => UserFixture::class,
'dataFile' => codecept_data_dir() . 'login_data.php'
]
];
}
/**
* @param FunctionalTester $I
*/
public function loginUser(FunctionalTester $I)
{
$I->amOnRoute('/site/login');
$I->fillField('Username', 'erau');
$I->fillField('Password', 'password_0');
$I->click('login-button');
$I->see('Logout (erau)', 'form button[type=submit]');
$I->dontSeeLink('Login');
$I->dontSeeLink('Signup');
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* Here you can initialize variables via \Codeception\Util\Fixtures class
* to store data in global array and use it in Cests.
*
* ```php
* // Here _bootstrap.php
* \Codeception\Util\Fixtures::add('user1', ['name' => 'davert']);
* ```
*
* In Cests
*
* ```php
* \Codeception\Util\Fixtures::get('user1');
* ```
*/

2
backend/tests/unit.suite.yml Executable file
View File

@ -0,0 +1,2 @@
suite_namespace: backend\tests\unit
actor: UnitTester

View File

@ -0,0 +1,16 @@
<?php
/**
* Here you can initialize variables via \Codeception\Util\Fixtures class
* to store data in global array and use it in Tests.
*
* ```php
* // Here _bootstrap.php
* \Codeception\Util\Fixtures::add('user1', ['name' => 'davert']);
* ```
*
* In Tests
*
* ```php
* \Codeception\Util\Fixtures::get('user1');
* ```
*/

33
backend/views/layouts/blank.php Executable file
View File

@ -0,0 +1,33 @@
<?php
/** @var yii\web\View $this */
/** @var string $content */
use backend\assets\AppAsset;
use yii\helpers\Html;
AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>" class="h-100">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<?php $this->registerCsrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body class="d-flex flex-column h-100">
<?php $this->beginBody() ?>
<main role="main">
<div class="container">
<?= $content ?>
</div>
</main>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage();

83
backend/views/layouts/main.php Executable file
View File

@ -0,0 +1,83 @@
<?php
/** @var \yii\web\View $this */
/** @var string $content */
use backend\assets\AppAsset;
use common\widgets\Alert;
use yii\bootstrap5\Breadcrumbs;
use yii\bootstrap5\Html;
use yii\bootstrap5\Nav;
use yii\bootstrap5\NavBar;
AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>" class="h-100">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<?php $this->registerCsrfMetaTags() ?>
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body class="d-flex flex-column h-100">
<?php $this->beginBody() ?>
<header>
<?php
NavBar::begin([
'brandLabel' => Yii::$app->name,
'brandUrl' => Yii::$app->homeUrl,
'options' => [
'class' => 'navbar navbar-expand-md navbar-dark bg-dark fixed-top',
],
]);
$menuItems = [
['label' => 'Home', 'url' => ['/site/index']],
['label' => 'Круд новостей', 'url' => ['/news/news']],
['label' => 'Круд профилей', 'url' => ['/profile/profile']],
];
if (Yii::$app->user->isGuest) {
$menuItems[] = ['label' => 'Login', 'url' => ['/site/login']];
}
echo Nav::widget([
'options' => ['class' => 'navbar-nav me-auto mb-2 mb-md-0'],
'items' => $menuItems,
]);
if (Yii::$app->user->isGuest) {
echo Html::tag('div',Html::a('Login',['/site/login'],['class' => ['btn btn-link login text-decoration-none']]),['class' => ['d-flex']]);
} else {
echo Html::beginForm(['/site/logout'], 'post', ['class' => 'd-flex'])
. Html::submitButton(
'Logout (' . Yii::$app->user->identity->username . ')',
['class' => 'btn btn-link logout text-decoration-none']
)
. Html::endForm();
}
NavBar::end();
?>
</header>
<main role="main" class="flex-shrink-0">
<div class="container">
<?= Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
<?= Alert::widget() ?>
<?= $content ?>
</div>
</main>
<footer class="footer mt-auto py-3 text-muted">
<div class="container">
<p class="float-start">&copy; <?= Html::encode(Yii::$app->name) ?> <?= date('Y') ?></p>
<p class="float-end"><?= Yii::powered() ?></p>
</div>
</footer>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage();

27
backend/views/site/error.php Executable file
View File

@ -0,0 +1,27 @@
<?php
/** @var yii\web\View $this */
/** @var string $name */
/** @var string $message */
/** @var Exception $exception*/
use yii\helpers\Html;
$this->title = $name;
?>
<div class="site-error">
<h1><?= Html::encode($this->title) ?></h1>
<div class="alert alert-danger">
<?= nl2br(Html::encode($message)) ?>
</div>
<p>
The above error occurred while the Web server was processing your request.
</p>
<p>
Please contact us if you think this is a server error. Thank you.
</p>
</div>

53
backend/views/site/index.php Executable file
View File

@ -0,0 +1,53 @@
<?php
/** @var yii\web\View $this */
$this->title = 'My Yii Application';
?>
<div class="site-index">
<div class="jumbotron text-center bg-transparent">
<h1 class="display-4">Congratulations!</h1>
<p class="lead">You have successfully created your Yii-powered application.</p>
<p><a class="btn btn-lg btn-success" href="http://www.yiiframework.com">Get started with Yii</a></p>
</div>
<div class="body-content">
<div class="row">
<div class="col-lg-4">
<h2>Heading</h2>
<p>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.</p>
<p><a class="btn btn-outline-secondary" href="http://www.yiiframework.com/doc/">Yii Documentation &raquo;</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>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.</p>
<p><a class="btn btn-outline-secondary" href="http://www.yiiframework.com/forum/">Yii Forum &raquo;</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>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.</p>
<p><a class="btn btn-outline-secondary" href="http://www.yiiframework.com/extensions/">Yii Extensions &raquo;</a></p>
</div>
</div>
</div>
</div>

32
backend/views/site/login.php Executable file
View File

@ -0,0 +1,32 @@
<?php
/** @var yii\web\View $this */
/** @var yii\bootstrap5\ActiveForm $form */
/** @var \common\models\LoginForm $model */
use yii\bootstrap5\ActiveForm;
use yii\bootstrap5\Html;
$this->title = 'Login';
?>
<div class="site-login">
<div class="mt-5 offset-lg-3 col-lg-6">
<h1><?= Html::encode($this->title) ?></h1>
<p>Please fill out the following fields to login:</p>
<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
<?= $form->field($model, 'username')->textInput(['autofocus' => true]) ?>
<?= $form->field($model, 'password')->passwordInput() ?>
<?= $form->field($model, 'rememberMe')->checkbox() ?>
<div class="form-group">
<?= Html::submitButton('Login', ['class' => 'btn btn-primary btn-block', 'name' => 'login-button']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>

2
backend/web/assets/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

90
backend/web/css/site.css Executable file
View File

@ -0,0 +1,90 @@
main > .container {
padding: 70px 15px 20px;
}
.footer {
background-color: #f5f5f5;
font-size: .9em;
height: 60px;
}
.footer > .container {
padding-right: 15px;
padding-left: 15px;
}
.not-set {
color: #c55;
font-style: italic;
}
/* add sorting icons to gridview sort links */
a.asc:after, a.desc:after {
content: '';
left: 3px;
display: inline-block;
width: 0;
height: 0;
border: solid 5px transparent;
margin: 4px 4px 2px 4px;
background: transparent;
}
a.asc:after {
border-bottom: solid 7px #212529;
border-top-width: 0;
}
a.desc:after {
border-top: solid 7px #212529;
border-bottom-width: 0;
}
.grid-view th,
.grid-view td:last-child {
white-space: nowrap;
}
.grid-view .filters input,
.grid-view .filters select {
min-width: 50px;
}
.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;
}
/* align the logout "link" (button in form) of the navbar */
.nav li > form > button.logout {
padding-top: 7px;
color: rgba(255, 255, 255, 0.5);
}
@media(max-width:767px) {
.nav li > form > button.logout {
display:block;
text-align: left;
width: 100%;
padding: 10px 0;
}
}
.nav > li > form > button.logout:focus,
.nav > li > form > button.logout:hover {
text-decoration: none;
color: rgba(255, 255, 255, 0.75);
}
.nav > li > form > button.logout:focus {
outline: none;
}

BIN
backend/web/favicon.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

9
codeception.yml Executable file
View File

@ -0,0 +1,9 @@
# global codeception file to run tests from all apps
include:
- common
- frontend
- backend
paths:
output: console/runtime/output
settings:
colors: true

15
common/codeception.yml Executable file
View File

@ -0,0 +1,15 @@
namespace: common\tests
actor_suffix: Tester
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
bootstrap: _bootstrap.php
settings:
colors: true
memory_limit: 1024M
modules:
config:
Yii2:
configFile: 'config/codeception-local.php'

4
common/config/.gitignore vendored Executable file
View File

@ -0,0 +1,4 @@
codeception-local.php
main-local.php
params-local.php
test-local.php

View File

@ -0,0 +1,33 @@
<?php
/**
* This class only exists here for IDE (PHPStorm/Netbeans/...) autocompletion.
* This file is never included anywhere.
* Adjust this file to match classes configured in your application config, to enable IDE autocompletion for custom components.
* Example: A property phpdoc can be added in `__Application` class as `@property \vendor\package\Rollbar|__Rollbar $rollbar` and adding a class in this file
* ```php
* // @property of \vendor\package\Rollbar goes here
* class __Rollbar {
* }
* ```
*/
class Yii {
/**
* @var \yii\web\Application|\yii\console\Application|__Application
*/
public static $app;
}
/**
* @property yii\rbac\DbManager $authManager
* @property \yii\web\User|__WebUser $user
*
*/
class __Application {
}
/**
* @property app\models\User $identity
*/
class __WebUser {
}

5
common/config/bootstrap.php Executable file
View File

@ -0,0 +1,5 @@
<?php
Yii::setAlias('@common', dirname(__DIR__));
Yii::setAlias('@frontend', dirname(dirname(__DIR__)) . '/frontend');
Yii::setAlias('@backend', dirname(dirname(__DIR__)) . '/backend');
Yii::setAlias('@console', dirname(dirname(__DIR__)) . '/console');

13
common/config/main.php Executable file
View File

@ -0,0 +1,13 @@
<?php
return [
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'components' => [
'cache' => [
'class' => \yii\caching\FileCache::class,
],
],
];

9
common/config/params.php Executable file
View File

@ -0,0 +1,9 @@
<?php
return [
'adminEmail' => 'admin@example.com',
'supportEmail' => 'support@example.com',
'senderEmail' => 'noreply@example.com',
'senderName' => 'Example.com mailer',
'user.passwordResetTokenExpire' => 3600,
'user.passwordMinLength' => 8,
];

11
common/config/test.php Executable file
View File

@ -0,0 +1,11 @@
<?php
return [
'id' => 'app-common-tests',
'basePath' => dirname(__DIR__),
'components' => [
'user' => [
'class' => \yii\web\User::class,
'identityClass' => 'common\models\User',
],
],
];

10
common/fixtures/UserFixture.php Executable file
View File

@ -0,0 +1,10 @@
<?php
namespace common\fixtures;
use yii\test\ActiveFixture;
class UserFixture extends ActiveFixture
{
public $modelClass = 'common\models\User';
}

View File

@ -0,0 +1,16 @@
<?php
use yii\helpers\Html;
/** @var yii\web\View $this */
/** @var common\models\User $user */
$verifyLink = Yii::$app->urlManager->createAbsoluteUrl(['site/verify-email', 'token' => $user->verification_token]);
?>
<div class="verify-email">
<p>Hello <?= Html::encode($user->username) ?>,</p>
<p>Follow the link below to verify your email:</p>
<p><?= Html::a(Html::encode($verifyLink), $verifyLink) ?></p>
</div>

View File

@ -0,0 +1,12 @@
<?php
/** @var yii\web\View $this */
/** @var common\models\User $user */
$verifyLink = Yii::$app->urlManager->createAbsoluteUrl(['site/verify-email', 'token' => $user->verification_token]);
?>
Hello <?= $user->username ?>,
Follow the link below to verify your email:
<?= $verifyLink ?>

24
common/mail/layouts/html.php Executable file
View File

@ -0,0 +1,24 @@
<?php
use yii\helpers\Html;
/** @var \yii\web\View $this view component instance */
/** @var \yii\mail\MessageInterface $message the message being composed */
/** @var string $content main view render result */
?>
<?php $this->beginPage() ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" />
<title><?= Html::encode($this->title) ?></title>
<?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<?= $content ?>
<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage();

12
common/mail/layouts/text.php Executable file
View File

@ -0,0 +1,12 @@
<?php
/** @var \yii\web\View $this view component instance */
/** @var \yii\mail\MessageInterface $message the message being composed */
/** @var string $content main view render result */
?>
<?php $this->beginPage() ?>
<?php $this->beginBody() ?>
<?= $content ?>
<?php $this->endBody() ?>
<?php $this->endPage() ?>

View File

@ -0,0 +1,16 @@
<?php
use yii\helpers\Html;
/** @var yii\web\View $this */
/** @var common\models\User $user */
$resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]);
?>
<div class="password-reset">
<p>Hello <?= Html::encode($user->username) ?>,</p>
<p>Follow the link below to reset your password:</p>
<p><?= Html::a(Html::encode($resetLink), $resetLink) ?></p>
</div>

View File

@ -0,0 +1,12 @@
<?php
/** @var yii\web\View $this */
/** @var common\models\User $user */
$resetLink = Yii::$app->urlManager->createAbsoluteUrl(['site/reset-password', 'token' => $user->password_reset_token]);
?>
Hello <?= $user->username ?>,
Follow the link below to reset your password:
<?= $resetLink ?>

79
common/models/LoginForm.php Executable file
View File

@ -0,0 +1,79 @@
<?php
namespace common\models;
use Yii;
use yii\base\Model;
/**
* Login form
*/
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;
private $_user;
/**
* {@inheritdoc}
*/
public function rules()
{
return [
// username and password are both required
[['username', 'password'], 'required'],
// rememberMe must be a boolean value
['rememberMe', 'boolean'],
// password is validated by validatePassword()
['password', 'validatePassword'],
];
}
/**
* Validates the password.
* This method serves as the inline validation for password.
*
* @param string $attribute the attribute currently being validated
* @param array $params the additional name-value pairs given in the rule
*/
public function validatePassword($attribute, $params)
{
if (!$this->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 bool 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);
}
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;
}
}

47
common/models/News.php Executable file
View File

@ -0,0 +1,47 @@
<?php
namespace common\models;
/**
* This is the model class for table "news".
*
* @property int $id
* @property string|null $title
* @property string|null $text
* @property string|null $slug
*/
class News extends \yii\db\ActiveRecord
{
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'news';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['text'], 'string'],
[['title', 'slug'], 'string', 'max' => 255],
[['slug'], 'unique'],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'title' => 'Title',
'text' => 'Text',
'slug' => 'Slug',
];
}
}

95
common/models/Profile.php Executable file
View File

@ -0,0 +1,95 @@
<?php
namespace common\models;
/**
* This is the model class for table "profile".
*
* @property int $id
* @property int|null $user_id
* @property string|null $created_at
* @property string|null $image
* @property int|null $activity
*
* @property Text[] $texts
* @property User $user
*/
class Profile extends \yii\db\ActiveRecord
{
public $file;
const STATUS_ACTIVE = 1;
const STATUS_INACTIVE = 0;
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'profile';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['user_id', 'activity'], 'integer'],
[['created_at'], 'safe'],
[['image'], 'string', 'max' => 255],
[['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::class, 'targetAttribute' => ['user_id' => 'id']],
[['file'], 'file', 'extensions' => 'jpg, png'],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'user_id' => 'Пользователь',
'created_at' => 'Когда создан',
'image' => 'Картинка',
'activity' => 'Активность',
];
}
/**
* Gets query for [[Texts]].
*
* @return \yii\db\ActiveQuery
*/
public function getTexts()
{
return $this->hasMany(Text::class, ['profile_id' => 'id']);
}
/**
* Gets query for [[User]].
*
* @return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne(User::class, ['id' => 'user_id']);
}
public function getStatusLabel()
{
if ($this->activity == self::STATUS_ACTIVE)
return 'Активен';
else
return 'Не активен';
}
/**
* @param string $lang
* @return \yii\db\ActiveQuery
*/
public function getTextByLanguage(string $lang)
{
return $this->hasMany(Text::class, ['profile_id' => 'id', 'language' => $lang]);
}
}

78
common/models/Text.php Executable file
View File

@ -0,0 +1,78 @@
<?php
namespace common\models;
/**
* This is the model class for table "text".
*
* @property int $id
* @property int|null $profile_id
* @property string|null $title
* @property string|null $text
* @property string|null $language
*
* @property Profile $profile
*/
class Text extends \yii\db\ActiveRecord
{
const LANG_RU = 'ru';
const LANG_EN = 'en';
const LANG_FR = 'fr';
const LANG_ES = 'es';
const LANG_IT = 'it';
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'text';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['profile_id'], 'integer'],
[['text'], 'string'],
[['title', 'language'], 'string', 'max' => 255],
[['profile_id'], 'exist', 'skipOnError' => true, 'targetClass' => Profile::class, 'targetAttribute' => ['profile_id' => 'id']],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'profile_id' => 'Profile ID',
'title' => 'Title',
'text' => 'Text',
'language' => 'Language',
];
}
public function extraFields()
{
return ['text[]', 'title[]'];
}
/**
* Gets query for [[Profile]].
*
* @return \yii\db\ActiveQuery
*/
public function getProfile()
{
return $this->hasOne(Profile::class, ['id' => 'profile_id']);
}
public static function getLanguages()
{
return [self::LANG_RU, self::LANG_IT, self::LANG_FR, self::LANG_EN, self::LANG_ES];
}
}

213
common/models/User.php Executable file
View File

@ -0,0 +1,213 @@
<?php
namespace common\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
/**
* User model
*
* @property integer $id
* @property string $username
* @property string $password_hash
* @property string $password_reset_token
* @property string $verification_token
* @property string $email
* @property string $auth_key
* @property integer $status
* @property integer $created_at
* @property integer $updated_at
* @property string $password write-only password
*/
class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_INACTIVE = 9;
const STATUS_ACTIVE = 10;
/**
* {@inheritdoc}
*/
public static function tableName()
{
return '{{%user}}';
}
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
TimestampBehavior::class,
];
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_INACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE, 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 user by verification email token
*
* @param string $token verify email token
* @return static|null
*/
public static function findByVerificationToken($token) {
return static::findOne([
'verification_token' => $token,
'status' => self::STATUS_INACTIVE
]);
}
/**
* Finds out if password reset token is valid
*
* @param string $token password reset token
* @return bool
*/
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 bool 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();
}
/**
* Generates new token for email verification
*/
public function generateEmailVerificationToken()
{
$this->verification_token = Yii::$app->security->generateRandomString() . '_' . time();
}
/**
* Removes password reset token
*/
public function removePasswordResetToken()
{
$this->password_reset_token = null;
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace common\services;
use common\models\Text;
use common\models\User;
use yii\web\UploadedFile;
class UserService
{
public function saveTexts($post, $profile_id, $texts)
{
foreach ($texts as $text) {
$text->text = $post['text'][$text->language];
$text->title = $post['title'][$text->language];
$text->profile_id = $profile_id;
$text->save();
}
}
public function saveProfile($post, $model)
{
$model->load($post);
$model->created_at = date('Y-d-m h:i:s');
$model->file = UploadedFile::getInstance($model, 'file');
if ($model->file) {
$model->image = $model->file->baseName . '.' . $model->file->extension;
$model->file->saveAs('@frontend/web/uploads/' . $model->file->baseName . '.' . $model->file->extension);
$model->file = null;
}
if ($model->save()) {
return true;
} else
return false;
}
public function getAllUsers()
{
return $users = User::find()->all();
}
public function newTexts()
{
$texts = [];
foreach (Text::getLanguages() as $lang) {
$text = new Text();
$text->language = $lang;
$texts[] = $text;
}
return $texts;
}
public function getTexts($id)
{
$textModels = Text::find()->where(['profile_id' => $id])->all();
// foreach ($textModels as $text)
// {
// $text->title[$text->language] = $text->title;
// $text->text[$text->language] = $text->text;
// }
return $textModels;
}
public function getTextByLanguage($id, $slug)
{
return Text::find()->where(['language' => $slug, 'profile_id' => $id])->all();
}
public static function run()
{
return new self();
}
}

9
common/tests/_bootstrap.php Executable file
View File

@ -0,0 +1,9 @@
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
defined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', __DIR__.'/../../');
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
require __DIR__ . '/../config/bootstrap.php';

14
common/tests/_data/user.php Executable file
View File

@ -0,0 +1,14 @@
<?php
return [
[
'username' => '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',
],
];

2
common/tests/_output/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
*
!.gitignore

1
common/tests/_support/.gitignore vendored Executable file
View File

@ -0,0 +1 @@
_generated

View File

@ -0,0 +1,26 @@
<?php
namespace common\tests;
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void verify($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}

7
common/tests/unit.suite.yml Executable file
View File

@ -0,0 +1,7 @@
suite_namespace: common\tests\unit
actor: UnitTester
bootstrap: false
modules:
enabled:
- Yii2:
part: fixtures

View File

@ -0,0 +1,67 @@
<?php
namespace common\tests\unit\models;
use Yii;
use common\models\LoginForm;
use common\fixtures\UserFixture;
/**
* Login form test
*/
class LoginFormTest extends \Codeception\Test\Unit
{
/**
* @var \common\tests\UnitTester
*/
protected $tester;
/**
* @return array
*/
public function _fixtures()
{
return [
'user' => [
'class' => UserFixture::class,
'dataFile' => codecept_data_dir() . 'user.php'
]
];
}
public function testLoginNoUser()
{
$model = new LoginForm([
'username' => 'not_existing_username',
'password' => 'not_existing_password',
]);
verify($model->login())->false();
verify(Yii::$app->user->isGuest)->true();
}
public function testLoginWrongPassword()
{
$model = new LoginForm([
'username' => 'bayer.hudson',
'password' => 'wrong_password',
]);
verify($model->login())->false();
verify( $model->errors)->arrayHasKey('password');
verify(Yii::$app->user->isGuest)->true();
}
public function testLoginCorrect()
{
$model = new LoginForm([
'username' => 'bayer.hudson',
'password' => 'password_0',
]);
verify($model->login())->true();
verify($model->errors)->arrayHasNotKey('password');
verify(Yii::$app->user->isGuest)->false();
}
}

76
common/widgets/Alert.php Executable file
View File

@ -0,0 +1,76 @@
<?php
namespace common\widgets;
use Yii;
/**
* Alert widget renders a message from session flash. All flash messages are displayed
* in the sequence they were assigned using setFlash. You can set message as following:
*
* ```php
* Yii::$app->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 <kartikv2@gmail.com>
* @author Alexander Makarov <sam@rmcreative.ru>
*/
class Alert extends \yii\bootstrap5\Widget
{
/**
* @var array the alert types configuration for the flash messages.
* This array is setup as $key => $value, where:
* - key: the name of the session flash variable
* - value: 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.
* Array will be passed to [[\yii\bootstrap\Alert::closeButton]].
*/
public $closeButton = [];
/**
* {@inheritdoc}
*/
public function run()
{
$session = Yii::$app->session;
$flashes = $session->getAllFlashes();
$appendClass = isset($this->options['class']) ? ' ' . $this->options['class'] : '';
foreach ($flashes as $type => $flash) {
if (!isset($this->alertTypes[$type])) {
continue;
}
foreach ((array) $flash as $i => $message) {
echo \yii\bootstrap5\Alert::widget([
'body' => $message,
'closeButton' => $this->closeButton,
'options' => array_merge($this->options, [
'id' => $this->getId() . '-' . $type . '-' . $i,
'class' => $this->alertTypes[$type] . $appendClass,
]),
]);
}
$session->removeFlash($type);
}
}
}

56
composer.json Executable file
View File

@ -0,0 +1,56 @@
{
"name": "yiisoft/yii2-app-advanced",
"description": "Yii 2 Advanced Project Template",
"keywords": ["yii2", "framework", "advanced", "project template"],
"homepage": "https://www.yiiframework.com/",
"type": "project",
"license": "BSD-3-Clause",
"support": {
"issues": "https://github.com/yiisoft/yii2/issues?state=open",
"forum": "https://www.yiiframework.com/forum/",
"wiki": "https://www.yiiframework.com/wiki/",
"irc": "irc://irc.freenode.net/yii",
"source": "https://github.com/yiisoft/yii2"
},
"minimum-stability": "stable",
"require-dev": {
"yiisoft/yii2-debug": "~2.1.0",
"yiisoft/yii2-gii": "~2.2.0",
"yiisoft/yii2-faker": "~2.0.0",
"phpunit/phpunit": "~9.5.0",
"codeception/codeception": "^5.0.0 || ^4.0",
"codeception/lib-innerbrowser": "^3.0 || ^1.1",
"codeception/module-asserts": "^3.0 || ^1.1",
"codeception/module-yii2": "^1.1",
"codeception/module-filesystem": "^2.0 || ^1.1",
"codeception/verify": "^2.2",
"symfony/browser-kit": "^6.0 || >=2.7 <=4.2.4"
},
"autoload-dev": {
"psr-4": {
"common\\tests\\": ["common/tests/", "common/tests/_support"],
"backend\\tests\\": ["backend/tests/", "backend/tests/_support"],
"frontend\\tests\\": ["frontend/tests/", "frontend/tests/_support"]
}
},
"config": {
"allow-plugins": {
"yiisoft/yii2-composer" : true
},
"process-timeout": 1800,
"fxp-asset": {
"enabled": false
}
},
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
],
"require": {
"yiisoft/yii2-bootstrap5": "@dev",
"kartik-v/yii2-widget-fileinput": "@dev",
"asmoday74/yii2-ckeditor5": "*"
}
}

5183
composer.lock generated Executable file

File diff suppressed because it is too large Load Diff

3
console/config/.gitignore vendored Executable file
View File

@ -0,0 +1,3 @@
main-local.php
params-local.php
test-local.php

1
console/config/bootstrap.php Executable file
View File

@ -0,0 +1 @@
<?php

36
console/config/main.php Executable file
View File

@ -0,0 +1,36 @@
<?php
$params = array_merge(
require __DIR__ . '/../../common/config/params.php',
require __DIR__ . '/../../common/config/params-local.php',
require __DIR__ . '/params.php',
require __DIR__ . '/params-local.php'
);
return [
'id' => 'app-console',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'controllerNamespace' => 'console\controllers',
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
'controllerMap' => [
'fixture' => [
'class' => \yii\console\controllers\FixtureController::class,
'namespace' => 'common\fixtures',
],
],
'components' => [
'log' => [
'targets' => [
[
'class' => \yii\log\FileTarget::class,
'levels' => ['error', 'warning'],
],
],
],
],
'params' => $params,
];

5
console/config/params.php Executable file
View File

@ -0,0 +1,5 @@
<?php
return [
'adminEmail' => 'admin@example.com',
];

4
console/config/test.php Executable file
View File

@ -0,0 +1,4 @@
<?php
return [
];

0
console/controllers/.gitkeep Executable file
View File

View File

@ -0,0 +1,33 @@
<?php
use yii\db\Migration;
class m130524_201442_init extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->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}}');
}
}

View File

@ -0,0 +1,16 @@
<?php
use \yii\db\Migration;
class m190124_110200_add_verification_token_column_to_user_table extends Migration
{
public function up()
{
$this->addColumn('{{%user}}', 'verification_token', $this->string()->defaultValue(null));
}
public function down()
{
$this->dropColumn('{{%user}}', 'verification_token');
}
}

View File

@ -0,0 +1,30 @@
<?php
use yii\db\Migration;
/**
* Handles the creation of table `{{%news}}`.
*/
class m230503_111312_create_news_table extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('{{%news}}', [
'id' => $this->primaryKey(),
'title' => $this->string(),
'text' => $this->text(),
'slug' => $this->string()->unique()
]);
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropTable('{{%news}}');
}
}

View File

@ -0,0 +1,33 @@
<?php
use yii\db\Migration;
/**
* Handles the creation of table `{{%profile}}`.
*/
class m230503_151339_create_profile_table extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('{{%profile}}', [
'id' => $this->primaryKey(),
'user_id' => $this->integer(),
'created_at' => $this->timestamp(),
'image' => $this->string(),
'activity' => $this->tinyInteger()
]);
$this->addForeignKey('user_foreign', 'profile', 'user_id', 'user', 'id');
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropForeignKey('user_foreign', 'profile');
$this->dropTable('{{%profile}}');
}
}

View File

@ -0,0 +1,33 @@
<?php
use yii\db\Migration;
/**
* Handles the creation of table `{{%text}}`.
*/
class m230503_151354_create_text_table extends Migration
{
/**
* {@inheritdoc}
*/
public function safeUp()
{
$this->createTable('{{%text}}', [
'id' => $this->primaryKey(),
'profile_id' => $this->integer(),
'title' => $this->string(),
'text' => $this->text(),
'language' => $this->string()
]);
$this->addForeignKey('profile_foreign', 'text', 'profile_id', 'profile', 'id');
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
$this->dropForeignKey('profile_foreign', 'text');
$this->dropTable('{{%text}}');
}
}

Some files were not shown because too many files have changed in this diff Show More