Jobs setup
This commit is contained in:
14
ui/common/Controller/Jobs.php
Normal file
14
ui/common/Controller/Jobs.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace ProVM\Common\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\Views\Blade as View;
|
||||
|
||||
class Jobs
|
||||
{
|
||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, View $view): ResponseInterface
|
||||
{
|
||||
return $view->render($response, 'jobs.list');
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ class Logging
|
||||
{
|
||||
$response = $handler->handle($request);
|
||||
$output = [
|
||||
'uri' => var_export($request->getUri(), true),
|
||||
'uri' => print_r($request->getUri(), true),
|
||||
'body' => $request->getParsedBody()
|
||||
];
|
||||
$this->getLogger()->info(\Safe\json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
|
||||
|
@ -3,6 +3,9 @@ server {
|
||||
root /app/ui/public;
|
||||
index index.php index.html index.htm;
|
||||
|
||||
access_log /var/logs/nginx/ui.access.log;
|
||||
error_log /var/logs/nginx/ui.error.log;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
@ -16,4 +19,4 @@ server {
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,5 @@ Monolog\ErrorHandler::register($app->getContainer()->get(Psr\Log\LoggerInterface
|
||||
try {
|
||||
$app->run();
|
||||
} catch (Error | Exception $e) {
|
||||
$logger = $app->getContainer()->get(Psr\Log\LoggerInterface::class);
|
||||
if (isset($_REQUEST)) {
|
||||
$logger->debug(Safe\json_encode(compact('_REQUEST')));
|
||||
}
|
||||
$logger->debug(Safe\json_encode(compact('_SERVER')));
|
||||
$logger->error($e);
|
||||
throw $e;
|
||||
$app->getContainer()->get(Psr\Log\LoggerInterface::class)->error($e);
|
||||
}
|
||||
|
4
ui/resources/routes/03_jobs.php
Normal file
4
ui/resources/routes/03_jobs.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
use ProVM\Common\Controller\Jobs;
|
||||
|
||||
$app->get('/jobs', Jobs::class);
|
@ -5,7 +5,12 @@
|
||||
<div id="messages" class="ui basic segment"></div>
|
||||
@endsection
|
||||
|
||||
@push('page_styles')
|
||||
<link rel="stylesheet" href="//cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" />
|
||||
@endpush
|
||||
|
||||
@push('page_scripts')
|
||||
<script type="text/javascript" src="//cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
class Message
|
||||
{
|
||||
@ -22,7 +27,8 @@
|
||||
}
|
||||
attachments
|
||||
|
||||
constructor({id, uid, subject, date_time, from, states, attachments}) {
|
||||
constructor({id, uid, subject, date_time, from, states, attachments})
|
||||
{
|
||||
this.set().id(id)
|
||||
.set().uid(uid)
|
||||
.set().subject(subject)
|
||||
@ -31,7 +37,8 @@
|
||||
.set().states(states)
|
||||
.set().attachments(attachments)
|
||||
}
|
||||
get() {
|
||||
get()
|
||||
{
|
||||
return {
|
||||
id: () => {
|
||||
return this.id
|
||||
@ -56,7 +63,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
set() {
|
||||
set()
|
||||
{
|
||||
return {
|
||||
id: id => {
|
||||
this.id = id
|
||||
@ -99,7 +107,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
has() {
|
||||
has()
|
||||
{
|
||||
return {
|
||||
attachments: () => {
|
||||
return this.states.attachments
|
||||
@ -115,7 +124,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
doesHave() {
|
||||
doesHave()
|
||||
{
|
||||
return {
|
||||
attachments: () => {
|
||||
this.states.attachments = true
|
||||
@ -136,7 +146,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
draw() {
|
||||
draw()
|
||||
{
|
||||
return {
|
||||
row: () => {
|
||||
const format = Intl.DateTimeFormat('es-CL', {dateStyle: 'full', timeStyle: 'short'})
|
||||
@ -196,14 +207,15 @@
|
||||
})
|
||||
},
|
||||
scheduledButton: () => {
|
||||
return $('<i></i>').addClass('ui green circular inverted check icon')
|
||||
return $('<i></i>').addClass('ui green circle check icon')
|
||||
},
|
||||
schedulingButton: () => {
|
||||
return $('<i></i>').addClass('ui circular inverted redo loading icon')
|
||||
return $('<i></i>').addClass('ui circle redo loading icon')
|
||||
}
|
||||
}
|
||||
}
|
||||
download() {
|
||||
download()
|
||||
{
|
||||
return {
|
||||
attachments: event => {
|
||||
const td = $(event.currentTarget).parent()
|
||||
@ -218,7 +230,11 @@
|
||||
return Send.put({
|
||||
uri,
|
||||
data
|
||||
}).then(response => {
|
||||
}).then((response, status, jqXHR) => {
|
||||
if (parseInt(jqXHR.status/100) !== 2 || jqXHR.status === 204) {
|
||||
td.html('')
|
||||
return
|
||||
}
|
||||
if (response.scheduled > 0) {
|
||||
td.html('').append(this.draw().scheduledButton())
|
||||
}
|
||||
@ -265,6 +281,7 @@
|
||||
$(this.id.results).html('').append(
|
||||
this.draw().table()
|
||||
)
|
||||
let table = new DataTable('#messages_table')
|
||||
} else {
|
||||
$(this.id.results).html('').append(
|
||||
this.draw().empty()
|
||||
@ -290,7 +307,7 @@
|
||||
)
|
||||
},
|
||||
table: () => {
|
||||
return $('<table></table>').addClass('ui table').append(
|
||||
return $('<table></table>').attr('id', 'messages_table').addClass('ui table').append(
|
||||
this.draw().head()
|
||||
).append(
|
||||
this.draw().body()
|
||||
@ -325,7 +342,7 @@
|
||||
).append(
|
||||
$('<th></th>').html('Downloaded Attachments')
|
||||
).append(
|
||||
$('<th></th>')
|
||||
$('<th></th>').html('Schedule?')
|
||||
)
|
||||
)
|
||||
},
|
||||
@ -334,7 +351,7 @@
|
||||
this.visible.forEach((m, i) => {
|
||||
const row = m.draw().row()
|
||||
row.prepend(
|
||||
$('<td></td>').html(i + this.current + 1)
|
||||
$('<td></td>').html(i + 1)
|
||||
)
|
||||
tbody.append(row)
|
||||
})
|
||||
|
@ -50,8 +50,12 @@
|
||||
}
|
||||
const list = $('<div></div>').addClass('ui list')
|
||||
this.mailboxes.forEach(mb => {
|
||||
let count = ''
|
||||
if (typeof mb.last_checked !== 'undefined') {
|
||||
count = ' (' + mb.last_checked.count + ')'
|
||||
}
|
||||
list.append(
|
||||
$('<a></a>').addClass('item').attr('href', '{{$urls->base}}/emails/mailbox/' + mb.id).html(mb.name)
|
||||
$('<a></a>').addClass('item').attr('href', '{{$urls->base}}/emails/mailbox/' + mb.id).html(mb.name + count)
|
||||
)
|
||||
})
|
||||
parent.append(list)
|
||||
|
14
ui/resources/views/jobs/base.blade.php
Normal file
14
ui/resources/views/jobs/base.blade.php
Normal file
@ -0,0 +1,14 @@
|
||||
@extends('layout.base')
|
||||
|
||||
@section('page_title')
|
||||
Jobs
|
||||
@hasSection('jobs_title')
|
||||
-
|
||||
@yield('jobs_title')
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@section('page_content')
|
||||
<h1>Jobs</h1>
|
||||
@yield('jobs_content')
|
||||
@endsection
|
165
ui/resources/views/jobs/list.blade.php
Normal file
165
ui/resources/views/jobs/list.blade.php
Normal file
@ -0,0 +1,165 @@
|
||||
@extends('jobs.base')
|
||||
|
||||
@section('jobs_content')
|
||||
<div id="jobs" class="ui basic segment"></div>
|
||||
@endsection
|
||||
|
||||
@push('page_styles')
|
||||
<link rel="stylesheet" href="//cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" />
|
||||
@endpush
|
||||
|
||||
@push('page_scripts')
|
||||
<script type="text/javascript" src="//cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
class Job
|
||||
{
|
||||
id
|
||||
command
|
||||
arguments
|
||||
states
|
||||
|
||||
constructor(props)
|
||||
{
|
||||
this.id = props.id
|
||||
this.command = props.command
|
||||
this.arguments = props.arguments
|
||||
this.states = props.states
|
||||
}
|
||||
lastState()
|
||||
{
|
||||
return this.states.sort((a, b) => {
|
||||
const d1 = new Date(a.date.date)
|
||||
const d2 = new Date(b.date.date)
|
||||
return d1 - d2
|
||||
}).at(-1)
|
||||
}
|
||||
isPending()
|
||||
{
|
||||
return this.lastState().status === 1
|
||||
}
|
||||
draw()
|
||||
{
|
||||
return {
|
||||
row: () => {
|
||||
const status = this.isPending() ? 'yellow clock' : 'green check'
|
||||
const formatter = new Intl.DateTimeFormat('es-CL', {dateStyle: 'full', timeStyle: 'long'})
|
||||
const d = new Date(this.lastState().date.date)
|
||||
return $('<tr></tr>').attr('data-id', this.id).append(
|
||||
$('<td></td>').html(this.id)
|
||||
).append(
|
||||
$('<td></td>').html(this.command)
|
||||
).append(
|
||||
$('<td></td>').html(this.arguments)
|
||||
).append(
|
||||
$('<td></td>').append(
|
||||
$('<i></i>').addClass('ui icon ' + status)
|
||||
)
|
||||
).append(
|
||||
$('<td></td>').html(formatter.format(d))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
execute()
|
||||
{
|
||||
const uri = '/job/' + this.id + '/execute'
|
||||
Send.get(uri).then((response, status, jqXHR) => {
|
||||
console.debug(jqXHR.status)
|
||||
console.debug(response)
|
||||
})
|
||||
}
|
||||
}
|
||||
const jobs = {
|
||||
id: '',
|
||||
data: [],
|
||||
get: function() {
|
||||
return {
|
||||
jobs: () => {
|
||||
this.draw().loader()
|
||||
const uri = '/jobs'
|
||||
return Send.get(uri).then((response, status, jqXHR) => {
|
||||
if (parseInt(jqXHR.status/100) !== 2 || jqXHR.status === 204) {
|
||||
$(this.id).html('').append(
|
||||
this.draw().empty()
|
||||
)
|
||||
return
|
||||
}
|
||||
if (response.jobs.length === 0) {
|
||||
$(this.id).html('').append(
|
||||
this.draw().empty()
|
||||
)
|
||||
return
|
||||
}
|
||||
this.data = response.jobs.map(job => {
|
||||
return new Job(job)
|
||||
})
|
||||
this.draw().jobs()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
draw: function() {
|
||||
return {
|
||||
loader: () => {
|
||||
$(this.id).html('').append(
|
||||
$('<div></div>').addClass('ui segment').append(
|
||||
$('<p></p>').html(' ')
|
||||
).append(
|
||||
$('<div></div>').addClass('ui active dimmer').append(
|
||||
$('<div></div>').addClass('ui indeterminate elastic loader')
|
||||
)
|
||||
).append(
|
||||
$('<p></p>').html(' ')
|
||||
)
|
||||
)
|
||||
},
|
||||
empty: () => {
|
||||
return $('<div></div>').addClass('ui message').html('No messages found.')
|
||||
},
|
||||
jobs: () => {
|
||||
$(this.id).html('')
|
||||
const table = $('<table></table>').addClass('ui table').attr('id', 'jobs_table')
|
||||
table.append(
|
||||
this.draw().head()
|
||||
).append(
|
||||
this.draw().body()
|
||||
)
|
||||
$(this.id).append(table)
|
||||
const t = new DataTable('#jobs_table', {
|
||||
order: [[4, 'desc']]
|
||||
})
|
||||
},
|
||||
head: () => {
|
||||
return $('<thead></thead>').append(
|
||||
$('<tr></tr>').append(
|
||||
$('<th></th>').html('ID')
|
||||
).append(
|
||||
$('<th></th>').html('Command')
|
||||
).append(
|
||||
$('<th></th>').html('Arguments')
|
||||
).append(
|
||||
$('<th></th>').html('Status')
|
||||
).append(
|
||||
$('<th></th>').html('Date')
|
||||
)
|
||||
)
|
||||
},
|
||||
body: () => {
|
||||
const body = $('<tbody></tbody>')
|
||||
this.data.forEach(job => {
|
||||
body.append(job.draw().row())
|
||||
})
|
||||
return body
|
||||
}
|
||||
}
|
||||
},
|
||||
setup: function() {
|
||||
this.get().jobs()
|
||||
}
|
||||
}
|
||||
$().ready(() => {
|
||||
jobs.id = '#jobs'
|
||||
jobs.setup()
|
||||
})
|
||||
</script>
|
||||
@endpush
|
@ -1,5 +1,6 @@
|
||||
<nav class="ui menu">
|
||||
<a class="item" href="{{$urls->base}}">Inicio</a>
|
||||
<a class="item" href="{{$urls->base}}/emails/mailboxes">Register Mailboxes</a>
|
||||
<a class="item" href="{{$urls->base}}/jobs">Jobs</a>
|
||||
</nav>
|
||||
<br />
|
||||
|
@ -2,8 +2,13 @@
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
return [
|
||||
Monolog\Handler\DeduplicationHandler::class => function(ContainerInterface $container) {
|
||||
return new Monolog\Handler\DeduplicationHandler($container->get(Monolog\Handler\RotatingFileHandler::class));
|
||||
'log_processors' => function(ContainerInterface $container) {
|
||||
return [
|
||||
$container->get(Monolog\Processor\PsrLogMessageProcessor::class),
|
||||
$container->get(Monolog\Processor\WebProcessor::class),
|
||||
$container->get(Monolog\Processor\IntrospectionProcessor::class),
|
||||
$container->get(Monolog\Processor\MemoryPeakUsageProcessor::class)
|
||||
];
|
||||
},
|
||||
Monolog\Handler\RotatingFileHandler::class => function(ContainerInterface $container) {
|
||||
$handler = new Monolog\Handler\RotatingFileHandler($container->get('log_file'));
|
||||
@ -11,22 +16,23 @@ return [
|
||||
return $handler;
|
||||
},
|
||||
'request_logger' => function(ContainerInterface $container) {
|
||||
$logger = new Monolog\Logger('request_logger');
|
||||
$handler = new Monolog\Handler\RotatingFileHandler(implode(DIRECTORY_SEPARATOR, [$container->get('folders')->logs, 'requests.log']));
|
||||
$handler->setFormatter($container->get(Monolog\Formatter\SyslogFormatter::class));
|
||||
$dedupHandler = new Monolog\Handler\DeduplicationHandler($handler, null, Monolog\Level::Info);
|
||||
$logger->pushHandler($dedupHandler);
|
||||
$logger->pushProcessor($container->get(Monolog\Processor\PsrLogMessageProcessor::class));
|
||||
$logger->pushProcessor($container->get(Monolog\Processor\IntrospectionProcessor::class));
|
||||
$logger->pushProcessor($container->get(Monolog\Processor\MemoryUsageProcessor::class));
|
||||
return $logger;
|
||||
return new Monolog\Logger('request_logger', [
|
||||
(new Monolog\Handler\RotatingFileHandler(implode(DIRECTORY_SEPARATOR, [$container->get('folders')->logs, 'requests.log']))),
|
||||
], $container->get('log_processors'));
|
||||
},
|
||||
Psr\Log\LoggerInterface::class => function(ContainerInterface $container) {
|
||||
$logger = new Monolog\Logger('file_logger');
|
||||
$logger->pushHandler($container->get(Monolog\Handler\DeduplicationHandler::class));
|
||||
$logger->pushProcessor($container->get(Monolog\Processor\PsrLogMessageProcessor::class));
|
||||
$logger->pushProcessor($container->get(Monolog\Processor\IntrospectionProcessor::class));
|
||||
$logger->pushProcessor($container->get(Monolog\Processor\MemoryUsageProcessor::class));
|
||||
return $logger;
|
||||
return new Monolog\Logger('file', [
|
||||
new Monolog\Handler\FilterHandler(
|
||||
(new Monolog\Handler\RotatingFileHandler($container->get('log_file')))
|
||||
->setFormatter(new Monolog\Formatter\LineFormatter(null, null, true)),
|
||||
Monolog\Level::Error
|
||||
),
|
||||
new Monolog\Handler\FilterHandler(
|
||||
(new Monolog\Handler\RotatingFileHandler(implode(DIRECTORY_SEPARATOR, [$container->get('folders')->logs, 'debug.log'])))
|
||||
->setFormatter(new Monolog\Formatter\LineFormatter(null, null, true)),
|
||||
Monolog\Level::Debug,
|
||||
Monolog\Level::Warning
|
||||
)
|
||||
], $container->get('log_processors'));
|
||||
},
|
||||
];
|
||||
|
Reference in New Issue
Block a user