Update for logs
This commit is contained in:
parent
620dba2974
commit
7196007c21
8 changed files with 257 additions and 46 deletions
|
@ -700,6 +700,12 @@ class Routing
|
|||
'AdminLogs:info',
|
||||
'AdminLogs'
|
||||
);
|
||||
$r->add(
|
||||
$r::DUO,
|
||||
'/admin/logs/{action:\w+}/{hash}/{token}',
|
||||
'AdminLogs:action',
|
||||
'AdminLogsAction'
|
||||
);
|
||||
}
|
||||
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
|
|
|
@ -112,6 +112,26 @@ class LogViewer
|
|||
return $this->fileList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает путь к логу по его хэшу
|
||||
*/
|
||||
public function getPath(string $hash): ?string
|
||||
{
|
||||
return $this->hashList[$hash] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает имя лога
|
||||
*/
|
||||
public function getName(string $path): string
|
||||
{
|
||||
if (! \preg_match('%[\\\/]([^\\\/]++)$%D', $path, $matches)) {
|
||||
throw new RuntimeException("Can't extract filename from path '{$path}'");
|
||||
}
|
||||
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает общую информацию по логам
|
||||
* и генерирует кеш
|
||||
|
@ -153,12 +173,8 @@ class LogViewer
|
|||
|
||||
protected function generateInfo(string $file): array
|
||||
{
|
||||
if (! \preg_match('%[\\\/]([^\\\/]++)$%D', $file, $matches)) {
|
||||
throw new RuntimeException("Can't extract filename from path '{$file}'");
|
||||
}
|
||||
|
||||
$result = [
|
||||
'log_name' => $matches[1],
|
||||
'log_name' => $this->getName($file),
|
||||
'emergency' => 0,
|
||||
'alert' => 0,
|
||||
'critical' => 0,
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace ForkBB\Models\Pages\Admin;
|
|||
|
||||
use ForkBB\Models\Page;
|
||||
use ForkBB\Models\Pages\Admin;
|
||||
use Throwable;
|
||||
use function \ForkBB\__;
|
||||
|
||||
class Logs extends Admin
|
||||
{
|
||||
|
@ -22,11 +24,143 @@ class Logs extends Admin
|
|||
{
|
||||
$this->c->Lang->load('admin_logs');
|
||||
|
||||
$logsFiles = $this->c->LogViewer->files();
|
||||
$info = $this->c->LogViewer->info($logsFiles);
|
||||
|
||||
foreach ($info as $hash => &$cur) {
|
||||
$cur['linkView'] = $this->c->Router->link(
|
||||
'AdminLogsAction',
|
||||
[
|
||||
'action' => 'view',
|
||||
'hash' => $hash,
|
||||
]
|
||||
);
|
||||
$cur['linkDownload'] = $this->c->Router->link(
|
||||
'AdminLogsAction',
|
||||
[
|
||||
'action' => 'download',
|
||||
'hash' => $hash,
|
||||
]
|
||||
);
|
||||
$cur['linkDelete'] = $this->c->Router->link(
|
||||
'AdminLogsAction',
|
||||
[
|
||||
'action' => 'delete',
|
||||
'hash' => $hash,
|
||||
]
|
||||
);
|
||||
}
|
||||
unset($cur);
|
||||
|
||||
$this->nameTpl = 'admin/logs';
|
||||
$this->aIndex = 'logs';
|
||||
$logsFiles = $this->c->LogViewer->files();
|
||||
$this->logsInfo = $this->c->LogViewer->info($logsFiles);
|
||||
$this->logsInfo = $info;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function action(array $args, string $method): Page
|
||||
{
|
||||
if (! $this->c->Csrf->verify($args['token'], 'AdminLogsAction', $args)) {
|
||||
return $this->c->Message->message($this->c->Csrf->getError());
|
||||
}
|
||||
|
||||
$path = $this->c->LogViewer->getPath($args['hash']);
|
||||
|
||||
if (
|
||||
null === $path
|
||||
|| ! \is_file($path)
|
||||
) {
|
||||
return $this->c->Message->message('Not Found', true, 404);
|
||||
}
|
||||
|
||||
$this->c->Lang->load('admin_logs');
|
||||
|
||||
$this->aIndex = 'logs';
|
||||
|
||||
switch ($args['action']) {
|
||||
case 'view':
|
||||
return $this->view($path, $args, $method);
|
||||
case 'delete':
|
||||
return $this->delete($path, $args, $method);
|
||||
case 'download':
|
||||
return $this->download($path, $args, $method);
|
||||
default:
|
||||
return $this->c->Message->message('Not Found', true, 404);
|
||||
}
|
||||
}
|
||||
|
||||
protected function download(string $path, array $args, string $method): Page
|
||||
{
|
||||
$this->c->DEBUG = 0;
|
||||
$this->nameTpl = 'layouts/plain_raw';
|
||||
$this->plainRaw = \trim(\file_get_contents($path)); // ???? возможности XSendFile/Nginx использовать?
|
||||
|
||||
$this->header('Content-type', 'application/octet-stream')
|
||||
->header('Content-Transfer-Encoding', 'binary')
|
||||
->header('Content-Disposition', 'attachment; filename=' . $this->c->LogViewer->getName($path));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function delete(string $path, array $args, string $method): Page
|
||||
{
|
||||
if ('POST' === $method) {
|
||||
$v = $this->c->Validator->reset()
|
||||
->addRules([
|
||||
'delete' => 'string',
|
||||
])->addAliases([
|
||||
])->addArguments([
|
||||
]);
|
||||
|
||||
try {
|
||||
if (
|
||||
$v->validation($_POST)
|
||||
&& \unlink($path)
|
||||
) {
|
||||
return $this->c->Redirect->page('AdminLogs')->message('Log deleted redirect');
|
||||
}
|
||||
} catch (Throwable $e) { // ???? будет работать или нет?
|
||||
$this->c->Log->error('Delete log: failed', [
|
||||
'exception' => $e,
|
||||
'headers' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->c->Redirect->page('AdminLogs')->message('Failed to delete log redirect');
|
||||
}
|
||||
|
||||
$this->nameTpl = 'admin/form';
|
||||
$this->titleForm = 'Delete log head';
|
||||
$this->classForm = 'logdel';
|
||||
$this->form = $this->formDelete($path, $args);
|
||||
$this->aCrumbs[] = [
|
||||
$this->c->Router->link('AdminLogsAction', $args),
|
||||
__('Delete log head'),
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function formDelete(string $path, array $args): array
|
||||
{
|
||||
$form = [
|
||||
'action' => $this->c->Router->link('AdminLogsAction', $args),
|
||||
'hidden' => [], // токен в url передается для всех действий с логами
|
||||
'sets' => [],
|
||||
'btns' => [
|
||||
'delete' => [
|
||||
'type' => 'submit',
|
||||
'value' => __('Delete log %s', $this->c->LogViewer->getName($path)),
|
||||
],
|
||||
'cancel' => [
|
||||
'type' => 'btn',
|
||||
'value' => __('Cancel'),
|
||||
'link' => $this->c->Router->link('AdminLogs'),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,11 +39,23 @@ msgstr "Info"
|
|||
msgid "Level debug"
|
||||
msgstr "Debug"
|
||||
|
||||
msgid "View log"
|
||||
msgstr "View"
|
||||
msgid "View log %s"
|
||||
msgstr "View %s"
|
||||
|
||||
msgid "Download log"
|
||||
msgstr "Download"
|
||||
|
||||
msgid "Delete log"
|
||||
msgstr "Delete"
|
||||
|
||||
msgid "Delete log head"
|
||||
msgstr "Delete log"
|
||||
|
||||
msgid "Delete log %s"
|
||||
msgstr "Delete log %s"
|
||||
|
||||
msgid "Log deleted redirect"
|
||||
msgstr "Log deleted."
|
||||
|
||||
msgid "Failed to delete log redirect"
|
||||
msgstr "Failed to delete log."
|
||||
|
|
|
@ -39,11 +39,23 @@ msgstr "Info"
|
|||
msgid "Level debug"
|
||||
msgstr "Debug"
|
||||
|
||||
msgid "View log"
|
||||
msgstr "Открыть"
|
||||
msgid "View log %s"
|
||||
msgstr "Открыть %s"
|
||||
|
||||
msgid "Download log"
|
||||
msgstr "Скачать"
|
||||
|
||||
msgid "Delete log"
|
||||
msgstr "Удалить"
|
||||
|
||||
msgid "Delete log head"
|
||||
msgstr "Удалить лог"
|
||||
|
||||
msgid "Delete log %s"
|
||||
msgstr "Удалить лог %s"
|
||||
|
||||
msgid "Log deleted redirect"
|
||||
msgstr "Лог удален."
|
||||
|
||||
msgid "Failed to delete log redirect"
|
||||
msgstr "Лог не удалось удалить."
|
||||
|
|
|
@ -4,23 +4,35 @@
|
|||
<h2>{!! __('Logs') !!}</h2>
|
||||
<div>
|
||||
<fieldset>
|
||||
<p></p>
|
||||
<p class="f-lgp f-lgli">
|
||||
<span class="f-lgname"><span>{!! __('Log name') !!}</span></span>
|
||||
<span class="f-llv f-llvem"><span>{!! __('Level emergency') !!}</span></span>
|
||||
<span class="f-llv f-llval"><span>{!! __('Level alert') !!}</span></span>
|
||||
<span class="f-llv f-llvcr"><span>{!! __('Level critical') !!}</span></span>
|
||||
<span class="f-llv f-llver"><span>{!! __('Level error') !!}</span></span>
|
||||
<span class="f-llv f-llvwa"><span>{!! __('Level warning') !!}</span></span>
|
||||
<span class="f-llv f-llvno"><span>{!! __('Level notice') !!}</span></span>
|
||||
<span class="f-llv f-llvin"><span>{!! __('Level info') !!}</span></span>
|
||||
<span class="f-llv f-llvde"><span>{!! __('Level debug') !!}</span></span>
|
||||
<span class="f-logbt"></span>
|
||||
</p>
|
||||
<ul>
|
||||
@foreach ($p->logsInfo as $hash => $cur)
|
||||
<li class="f-lgli">
|
||||
<span class="f-lgname" title="{!! __('Log name') !!}">{{ $cur['log_name'] }}</span>
|
||||
<span class="f-llv f-llvem" title="{!! __('Level emergency') !!}">{{ num($cur['emergency']) }}</span>
|
||||
<span class="f-llv f-llval" title="{!! __('Level alert') !!}">{{ num($cur['alert']) }}</span>
|
||||
<span class="f-llv f-llvcr" title="{!! __('Level critical') !!}">{{ num($cur['critical']) }}</span>
|
||||
<span class="f-llv f-llver" title="{!! __('Level error') !!}">{{ num($cur['error']) }}</span>
|
||||
<span class="f-llv f-llvwa" title="{!! __('Level warning') !!}">{{ num($cur['warning']) }}</span>
|
||||
<span class="f-llv f-llvno" title="{!! __('Level notice') !!}">{{ num($cur['notice']) }}</span>
|
||||
<span class="f-llv f-llvin" title="{!! __('Level info') !!}">{{ num($cur['info']) }}</span>
|
||||
<span class="f-llv f-llvde" title="{!! __('Level debug') !!}">{{ num($cur['debug']) }}</span>
|
||||
<span class="f-lgname f-lgsname">
|
||||
<a class="f-lganame" href="{{ $cur['linkView'] }}" title="{!! __('View log %s', $cur['log_name']) !!}">{{ $cur['log_name'] }}</a>
|
||||
</span>
|
||||
<span class="f-llv @if ($cur['emergency']) f-llvem @endif" title="{!! __('Level emergency') !!}"><span>{{ num($cur['emergency']) }}</span></span>
|
||||
<span class="f-llv @if ($cur['alert']) f-llval @endif" title="{!! __('Level alert') !!}"><span>{{ num($cur['alert']) }}</span></span>
|
||||
<span class="f-llv @if ($cur['critical']) f-llvcr @endif" title="{!! __('Level critical') !!}"><span>{{ num($cur['critical']) }}</span></span>
|
||||
<span class="f-llv @if ($cur['error']) f-llver @endif" title="{!! __('Level error') !!}"><span>{{ num($cur['error']) }}</span></span>
|
||||
<span class="f-llv @if ($cur['warning']) f-llvwa @endif" title="{!! __('Level warning') !!}"><span>{{ num($cur['warning']) }}</span></span>
|
||||
<span class="f-llv @if ($cur['notice']) f-llvno @endif" title="{!! __('Level notice') !!}"><span>{{ num($cur['notice']) }}</span></span>
|
||||
<span class="f-llv @if ($cur['info']) f-llvin @endif" title="{!! __('Level info') !!}"><span>{{ num($cur['info']) }}</span></span>
|
||||
<span class="f-llv @if ($cur['debug']) f-llvde @endif" title="{!! __('Level debug') !!}"><span>{{ num($cur['debug']) }}</span></span>
|
||||
<span class="f-logbt">
|
||||
<a class="f-btn f-lga f-lgaview" href="" title="{!! __('View log') !!}"><span class="f-lgs">{!! __('View log') !!}</span></a>
|
||||
<a class="f-btn f-lga f-lgadown" href="" title="{!! __('Download log') !!}"><span class="f-lgs">{!! __('Download log') !!}</span></a>
|
||||
<a class="f-btn f-lga f-lgadel" href="" title="{!! __('Delete log') !!}"><span class="f-lgs">{!! __('Delete log') !!}</span></a>
|
||||
<a class="f-btn f-lga f-lgadown" href="{{ $cur['linkDownload'] }}" title="{!! __('Download log') !!}"><span class="f-lgs">{!! __('Download log') !!}</span></a>
|
||||
<a class="f-btn f-lga f-lgadel" href="{{ $cur['linkDelete'] }}" title="{!! __('Delete log') !!}"><span class="f-lgs">{!! __('Delete log') !!}</span></a>
|
||||
</span>
|
||||
</li>
|
||||
@endforeach
|
||||
|
|
1
app/templates/layouts/plain_raw.forkbb.php
Normal file
1
app/templates/layouts/plain_raw.forkbb.php
Normal file
|
@ -0,0 +1 @@
|
|||
{!! $p->plainRaw !!}
|
|
@ -3303,36 +3303,53 @@ html[lang="ru"] #fork details[open] > summary::after {
|
|||
display: flex;
|
||||
}
|
||||
|
||||
#forka .f-llvem {
|
||||
color: #B71C1C;
|
||||
#forka .f-lgp {
|
||||
border-top: 0.0625rem dotted #AA7939;
|
||||
}
|
||||
|
||||
#forka .f-llval {
|
||||
color: #D32F2F;
|
||||
#forka .f-llv > span {
|
||||
margin: 0.125rem 0.1875rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#forka .f-llvcr {
|
||||
color: #F44336;
|
||||
#forka .f-llvem > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #B71C1C;
|
||||
}
|
||||
|
||||
#forka .f-llver {
|
||||
color: #FF5722;
|
||||
#forka .f-llval > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #D32F2F;
|
||||
}
|
||||
|
||||
#forka .f-llvwa {
|
||||
color: #FF9100;
|
||||
#forka .f-llvcr > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #F44336;
|
||||
}
|
||||
|
||||
#forka .f-llvno {
|
||||
color: #4CAF50;
|
||||
#forka .f-llver > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #FF5722;
|
||||
}
|
||||
|
||||
#forka .f-llvin {
|
||||
color: #1976D2;
|
||||
#forka .f-llvwa > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #FF9100;
|
||||
}
|
||||
|
||||
#forka .f-llvde {
|
||||
color: #90CAF9;
|
||||
#forka .f-llvno > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
#forka .f-llvin > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #1976D2;
|
||||
}
|
||||
|
||||
#forka .f-llvde > span {
|
||||
color: #F8F4E3;
|
||||
background-color: #90CAF9;
|
||||
}
|
||||
|
||||
#forka .f-lgname {
|
||||
|
@ -3340,12 +3357,12 @@ html[lang="ru"] #fork details[open] > summary::after {
|
|||
}
|
||||
|
||||
#forka .f-logbt {
|
||||
width: 5rem;
|
||||
width: 3.25rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#forka .f-llv {
|
||||
width: calc( (100% - 13rem) / 8 );
|
||||
width: calc( (100% - 11.25rem) / 8 );
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -3358,10 +3375,6 @@ html[lang="ru"] #fork details[open] > summary::after {
|
|||
font-weight: 900;
|
||||
}
|
||||
|
||||
#forka .f-lgaview:before {
|
||||
content: "\f002";
|
||||
}
|
||||
|
||||
#forka .f-lgadown:before {
|
||||
content: "\f019";
|
||||
}
|
||||
|
@ -3374,6 +3387,11 @@ html[lang="ru"] #fork details[open] > summary::after {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#forka .f-logdel-form .f-fbtn {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/****************************************/
|
||||
@media screen and (min-width: 81rem) {
|
||||
#fork.f-with-nav {
|
||||
|
|
Loading…
Add table
Reference in a new issue