Этот коммит содержится в:
Igor V Belousov 2019-11-11 01:58:17 +03:00
родитель a54744ffb9
Коммит e2ac280221
26 изменённых файлов: 732 добавлений и 16 удалений

Просмотреть файл

@ -1,6 +1,98 @@
*, :after, :before {
-webkit-box-sizing: border-box;
box-sizing: border-box
}
a {
color: #0063ff;
text-decoration: none;
border-bottom: .0625rem solid rgba(0, 99, 255, .3);
}
a:hover,
a:visited:hover {
color: #ff475d;
border-bottom: .0625rem solid rgba(255, 71, 93, .24);
}
a:visited {
color: #cf00cf;
border-bottom: .0625rem solid rgba(207, 0, 207, .3);
}
body { body {
font-family: Verdana, "Geneva CY", "DejaVu Sans", sans-serif; font-family: Verdana, "Geneva CY", "DejaVu Sans", sans-serif;
font-size: 1rem; font-size: 1rem;
font-weight: normal; font-weight: normal;
line-height: 1.25rem;
} }
.header {
display: grid;
grid-template-rows: 1fr 1fr;
grid-template-columns: 1fr 6fr;
grid-gap: 1vw;
}
.header, .main, .footer, .navigate ul {
margin: 0 auto;
max-width: 1000px;
}
.header__img {
grid-row: 1/3;
grid-column: 1;
margin-left: -1.75rem;
margin-right: -1.75rem;
}
.header__title {
margin-bottom: 0;
line-height: 1;
margin-top: 3rem;
}
.navigate {
background: black;
margin-top: 1.25rem;
}
.navigate ul {
list-style: none unset none;
padding: .375rem 0;
}
.navigate ul li {
display: inline-block;
width: 32%;
text-align: center;
}
.navigate ul li a {
color: white;
text-decoration: none;
}
.navigate ul li a:hover {
color: white;
border-bottom: .0625rem solid rgba(255, 255, 255, .6);
}
.footer {
margin-top: 2rem;
padding-top: 1rem;
padding-bottom: 1rem;
}
.footer::before {
width: 100%;
display: block;
content: " ";
border-top: .25rem solid black;
position: absolute;
left: 0;
}
table {
border-collapse: collapse;
}

Просмотреть файл

@ -11,6 +11,7 @@ class App
'Controller\\' => 'controllers/', 'Controller\\' => 'controllers/',
'Core\\' => 'core/', 'Core\\' => 'core/',
'Model\\' => 'models/', 'Model\\' => 'models/',
'Service\\' => 'services/',
'View\\' => 'views/', 'View\\' => 'views/',
]; ];
private $basedir = __DIR__; private $basedir = __DIR__;
@ -26,7 +27,7 @@ class App
/** /**
* App constructor. * App constructor.
* *
* @param bool $start Start router. Default false. * @param bool $start Start router. Default true.
*/ */
public function __construct(bool $start = true) public function __construct(bool $start = true)
{ {

Просмотреть файл

@ -12,7 +12,6 @@ class DefaultController extends Controller
*/ */
public function index() public function index()
{ {
(new View())->index(); $this->htmlResponse((new View())->index());
$Model = new \MyApp\Model\GroupsModel();
} }
} }

Просмотреть файл

@ -3,13 +3,14 @@
namespace MyApp\Controller; namespace MyApp\Controller;
use MyApp\Core\Controller; use MyApp\Core\Controller;
use MyApp\Core\View;
class ErrorsController extends Controller class ErrorsController extends Controller
{ {
public function get404() public function get404()
{ {
http_response_code(404); $this->htmlResponse((new View())->setTitle('404 Page not found')->render('404'),
echo 404; 404);
} }
public function post404() public function post404()

43
src/controllers/GroupsController.php Обычный файл
Просмотреть файл

@ -0,0 +1,43 @@
<?php
namespace MyApp\Controller;
use MyApp\Core\Controller;
use MyApp\View\GroupsView as View;
use MyApp\Service\GroupsService;
class GroupsController extends Controller
{
/**
* @RouteRegExp = "|^/groups$|"
*/
public function index()
{
$this->htmlResponse((new View())->index((new GroupsService())->getTableData()));
}
/**
* @RouteRegExp = "|^/groups/add$|"
*/
public function add()
{
}
/**
* @RouteRegExp = "|^/groups/edit/(?<id>\d+)$|"
*/
public function edit($id)
{
$group_service = new GroupsService();
$model = $group_service->getGroup($id);
if ($model) {
$this->htmlResponse((new View())->edit($group_service->getGroup($id),
$group_service->getTableData()));
} else {
$this->redirect('/groups');
}
}
}

30
src/controllers/ServersController.php Обычный файл
Просмотреть файл

@ -0,0 +1,30 @@
<?php
namespace MyApp\Controller;
use MyApp\Core\Controller;
class ServersController extends Controller
{
/**
* @RouteRegExp = "|^/servers$|"
*/
public function index()
{
}
/**
* @RouteRegExp = "|^/servers/add$|"
*/
public function add()
{
}
/**
* @RouteRegExp = "|^/servers/edit/(?<id>\d+)$|"
*/
public function edit($id)
{
}
}

Просмотреть файл

@ -2,6 +2,9 @@
namespace MyApp\Core; namespace MyApp\Core;
/**
* Class Config.
*/
class Config class Config
{ {
/** /**

Просмотреть файл

@ -2,6 +2,49 @@
namespace MyApp\Core; namespace MyApp\Core;
/**
* Class Controller.
*/
class Controller class Controller
{ {
public function __construct()
{
}
/**
* Send JSON response.
*
* @param mixed $data
* @param int $http_response_code HTTP code. Default 200
*/
public function jsonResponse($data = null, $http_response_code = 200)
{
http_response_code($http_response_code);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_UNESCAPED_UNICODE);
exit(0);
}
/**
* Send html response.
*
* @param mixed $data
* @param int $http_response_code HTTP code. Default 200
*/
public function htmlResponse($data = null, $http_response_code = 200)
{
http_response_code($http_response_code);
header('Content-Type: text/html; charset=utf-8');
echo $data;
exit(0);
}
/**
* @param string $path
* @param int $http_response_code
*/
public function redirect( $path = '/', $http_response_code = 302 ) {
header( "Location: $path", true, $http_response_code );
exit;
}
} }

Просмотреть файл

@ -8,23 +8,36 @@ class View
* @var string * @var string
*/ */
public $title = ''; public $title = '';
/**
* @var string
*/
public $siteName = '';
public function json($data) public function __construct()
{ {
} }
public function render($template) /**
* @param string $template
*
* @return string
*/
public function render(string $template): string
{ {
/* @var \App $app */ /* @var \App $app */
global $app; global $app;
$fileName = $app->config->getSrcDir().'/templates/'.$template.'.tpl.php'; $fileName = $app->config->getSrcDir().'/templates/'.$template.'.tpl.php';
$out = '';
if (file_exists($fileName)) { if (file_exists($fileName)) {
ob_start(); ob_start();
require $fileName; require $fileName;
ob_end_flush(); $out = ob_get_contents();
ob_end_clean();
} }
return $out;
} }
/** /**
@ -37,7 +50,8 @@ class View
/* @var \App $app */ /* @var \App $app */
global $app; global $app;
$this->title = $title.' &mdash; '.$app->config->getSiteName(); $this->siteName = $app->config->getSiteName();
$this->title = $title;
return $this; return $this;
} }

Просмотреть файл

@ -74,4 +74,12 @@ class GroupsModel extends Model
$this->parent = $parent; $this->parent = $parent;
return $this; return $this;
} }
/**
* @return int
*/
public function getParent(): ?int
{
return $this->parent;
}
} }

Просмотреть файл

@ -1,13 +1,113 @@
<?php <?php
namespace MyApp\Model; namespace MyApp\Model;
use MyApp\Core\Model;
class ServersModel /**
* Class ServersModel.
*
* @TableName = "servers"
*
* @package MyApp\Model
*/
class ServersModel extends Model
{ {
/**
* @ColumnName = "id"
* @ColumnOption = "id"
* @ColumnType = "int unsigned auto_increment primary key"
*
* @var int
*/
private $id; private $id;
/**
* @ColumnName = "name"
* @ColumnType = "varchar(255) null"
*
* @var string
*/
private $name; private $name;
/**
* @ColumnName = "ip"
* @ColumnType = "int unsigned null"
*
* @var int
*/
private $ip; private $ip;
/**
* @ColumnName = "group_id"
* @ColumnType = "int unsigned null, constraint servers_groups_id_fk foreign key (group_id) references `groups` (id) on delete cascade"
*
* @var int
*/
private $group; private $group;
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*
* @return ServersModel
*/
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getIp(): string
{
return long2ip($this->ip);
}
/**
* @param string $ip
*
* @return ServersModel
*/
public function setIp(string $ip): self
{
$this->ip = ip2long($ip);
return $this;
}
/**
* @return int
*/
public function getGroup(): int
{
return $this->group;
}
/**
* @param int $group
*
* @return ServersModel
*/
public function setGroup(int $group): self
{
$this->group = $group;
return $this;
}
} }

146
src/models/TallyLogsModel.php Обычный файл
Просмотреть файл

@ -0,0 +1,146 @@
<?php
namespace MyApp\Model;
use MyApp\Core\Model;
use DateTime;
/**
* Class LogsModel.
*
* @TableName = "logs"
*/
class TallyLogsModel extends Model
{
/**
* @ColumnName = "id"
* @ColumnOption = "id"
* @ColumnType = "int unsigned auto_increment primary key"
*
* @var int
*/
private $id;
/**
* @ColumnName = "time"
* @ColumnType = "timestamp null"
*
* @var int
*/
private $time;
/**
* @ColumnName = "transmitted"
* @ColumnType = "int null"
*
* @var int
*/
private $transmitted;
/**
* @ColumnName = "received"
* @ColumnType = "int null"
*
* @var int
*/
private $received;
/**
* @ColumnName = "lost"
* @ColumnType = "int null"
*
* @var int
*/
private $lost;
/**
* @ColumnName = "server_id"
* @ColumnType = "int unsigned null, constraint logs_servers_id_fk foreign key (server_id) references `servers` (id) on delete cascade"
*
* @var int
*/
private $server;
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @return int
*/
public function getTime(): int
{
return $this->time;
}
/**
* @param DateTime $time
*
* @return TallyLogsModel
*/
public function setTime(DateTime $time): self
{
$this->time = $time->getTimestamp();
return $this;
}
/**
* @return int
*/
public function getTransmitted(): int
{
return $this->transmitted;
}
/**
* @param int $transmitted
*
* @return TallyLogsModel
*/
public function setTransmitted(int $transmitted): self
{
$this->transmitted = $transmitted;
return $this;
}
/**
* @return int
*/
public function getReceived(): int
{
return $this->received;
}
/**
* @param int $received
*
* @return TallyLogsModel
*/
public function setReceived(int $received): self
{
$this->received = $received;
return $this;
}
/**
* @return int
*/
public function getLost(): int
{
return $this->lost;
}
/**
* @param int $lost
*
* @return TallyLogsModel
*/
public function setLost(int $lost): self
{
$this->lost = $lost;
return $this;
}
}

34
src/services/GroupsService.php Обычный файл
Просмотреть файл

@ -0,0 +1,34 @@
<?php
namespace MyApp\Service;
use MyApp\Model\GroupsModel;
use Exception;
class GroupsService
{
/**
* @return GroupsModel[]|null
*
* @throws Exception
*/
public function getTableData(): ? array
{
$models = GroupsModel::find(null,null,'1 = 1');
return $models;
}
public function getGroup($id): ? GroupsModel
{
/** @var GroupsModel[] $model */
$model = GroupsModel::find([$id],null,null,[],'','1');
if (!empty($model)){
return $model[0];
}
return null;
}
}

38
src/services/PingService.php Обычный файл
Просмотреть файл

@ -0,0 +1,38 @@
<?php
namespace MyApp\Service;
use MyApp\Model\TallyLogsModel;
use MyApp\Core\Model;
use MyApp\Model\ServersModel;
use DateTime;
class PingService
{
public function ping($server_id): ? TallyLogsModel
{
$server = ServersModel::find([$server_id],null,null,[],'','1');
if (!empty($server)){
$ip = $server[0]->getIp();
exec("ping -c 10 $ip", $output, $status);
foreach ($output as $line) {
if (preg_match('/(?<transmitted>\d+)[\w\ ]*,\ (?<received>\d+)[\w\ ]*, (?<lost>\d+)%/',
$line, $m)) {
$log = new TallyLogsModel();
$log->setTime(new DateTime())
->setLost($m['lost'])
->setTransmitted($m['transmitted'])
->setReceived($m['received']);
Model::save([$log]);
return $log;
}
}
}
return null;
}
}

5
src/templates/404.tpl.php Обычный файл
Просмотреть файл

@ -0,0 +1,5 @@
<?php
require __DIR__ . '/shared/head.php';
?>
<?php
require __DIR__ . '/shared/footer.php';

Просмотреть файл

@ -1,3 +1,5 @@
<?php <?php
require __DIR__ . '/../shared/head.php'; ?>
require __DIR__.'/../shared/head.php'; <?php
require __DIR__ . '/../shared/footer.php';

7
src/templates/groups/add.tpl.php Обычный файл
Просмотреть файл

@ -0,0 +1,7 @@
<?php
require __DIR__ . '/../shared/head.php'; ?>
<form action="">
</form>
<?php
require __DIR__ . '/../shared/footer.php';

51
src/templates/groups/edit.tpl.php Обычный файл
Просмотреть файл

@ -0,0 +1,51 @@
<?php
require __DIR__ . '/../shared/head.php';
/** @var \MyApp\Model\GroupsModel $model */
$model = $this->model;
function getTree($table, $parent_id = null, $level = 1)
{
$out = [];
foreach ($table as $item) {
/** @var \MyApp\Model\GroupsModel $item */
if (
$item->getParent() === $parent_id) {
$item->{"select-level"} = str_repeat("-", $level);
$out[] = $item;
$out = array_merge($out,
getTree($table, $item->getId(), $level + 1));
}
}
return $out;
}
?>
<br>
<form action="" method="post">
<input type="hidden" value="<?= $model->getId() ?>" name="id">
<div>
<label for="parent">Parent:</label>
<select name="parent" id="parent">
<option value="null"
<?php if (is_null($model->getParent())): ?>selected<?php endif; ?>>
Root
</option>
<?php foreach (getTree($this->table) as $item): ?>
<option value="<?= $item->getId() ?>"
<?php if ($item->getId() === $model->getParent()): ?>selected<?php endif; ?>>
<?= $item->{"select-level"} ?><?= $item->getName() ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label for="name">Name:</label>
<input type="text" value="<?= $model->getName() ?>" name="name" id="name">
</div>
<button type="submit">Submit</button>
</form>
<?php
require __DIR__ . '/../shared/footer.php';

24
src/templates/groups/index.tpl.php Обычный файл
Просмотреть файл

@ -0,0 +1,24 @@
<?php
require __DIR__ . '/../shared/head.php'; ?>
<?php if ($this->table): ?>
<br>
<table border="1" width="100%">
<tr>
<th>Id</th>
<th>Name</th>
<th>Parent</th>
<th>Actions</th>
</tr>
<?php foreach ($this->table as $item):?>
<tr>
<td><?= $item->getId() ?></td>
<td><?= $item->getName() ?></td>
<td><?= $item->getParent() ?></td>
<td><a href="/groups/edit/<?= $item->getId() ?>">edit</a></td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
<?php
require __DIR__ . '/../shared/footer.php';

7
src/templates/servers/add.tpl.php Обычный файл
Просмотреть файл

@ -0,0 +1,7 @@
<?php
require __DIR__ . '/../shared/head.php'; ?>
<form action="">
</form>
<?php
require __DIR__ . '/../shared/footer.php';

7
src/templates/servers/index.tpl.php Обычный файл
Просмотреть файл

@ -0,0 +1,7 @@
<?php
require __DIR__ . '/../shared/head.php'; ?>
<table>
</table>
<?php
require __DIR__ . '/../shared/footer.php';

7
src/templates/shared/footer.php Обычный файл
Просмотреть файл

@ -0,0 +1,7 @@
</section>
<footer class="footer">
<br>
<a href="https://belousovv.ru" target="_blank">Belousovv.ru</a>
</footer>
</body>
</html>

Просмотреть файл

@ -14,5 +14,21 @@
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="/assets/css/normalize.css"> <link rel="stylesheet" href="/assets/css/normalize.css">
<link rel="stylesheet" href="/assets/css/style.css"> <link rel="stylesheet" href="/assets/css/style.css">
<title><?= $this->title; ?></title> <title><?= $this->title; ?> &mdash; <?= $this->siteName; ?></title>
</head> </head>
<body>
<header class="header">
<img class="header__img" src="/assets/img/favicon/android-chrome-384x384.png" alt="" height="192" width="192">
<h1 class="header__title"><?= $this->siteName; ?></h1>
<h2 class="header__title"><?= $this->title; ?></h2>
</header>
<nav class="navigate">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/servers">Edit servers</a></li>
<li><a href="/groups">Edit groups</a></li>
</ul>
</nav>
<section class="main">

Просмотреть файл

@ -6,8 +6,8 @@ use MyApp\Core\View;
class DefaultView extends View class DefaultView extends View
{ {
public function index() public function index(): string
{ {
$this->setTitle('Index')->render('default/index'); return $this->setTitle('Index')->render('default/index');
} }
} }

26
src/views/GroupsView.php Обычный файл
Просмотреть файл

@ -0,0 +1,26 @@
<?php
namespace MyApp\View;
use MyApp\Core\View;
class GroupsView extends View
{
public function index(?array $table)
{
$this->{"table"} = $table;
return $this->setTitle('Edit groups')->render('groups/index');
}
public function edit($model, ?array $table)
{
$this->{"model"} = $model;
$this->{"table"} = $table;
return $this->setTitle('Edit groups')->render('groups/edit');
}
}

12
src/views/ServersView.php Обычный файл
Просмотреть файл

@ -0,0 +1,12 @@
<?php
namespace MyApp\View;
use MyApp\Core\View;
class ServersView extends View
{
}