NEW FEATURE: editing jobs
This commit is contained in:
parent
497c8dc27c
commit
4cf6c649b6
|
@ -31,6 +31,13 @@ job_view:
|
||||||
requirements:
|
requirements:
|
||||||
id: \d+
|
id: \d+
|
||||||
|
|
||||||
|
job_edit:
|
||||||
|
path: '/job/{id}/edit'
|
||||||
|
defaults:
|
||||||
|
_controller: JeroenED\Webcron\Controller\JobController::editAction
|
||||||
|
requirements:
|
||||||
|
id: \d+
|
||||||
|
|
||||||
job_add:
|
job_add:
|
||||||
path: '/job/add'
|
path: '/job/add'
|
||||||
defaults:
|
defaults:
|
||||||
|
|
|
@ -10,8 +10,8 @@ $(function() {
|
||||||
|
|
||||||
function initDatePickers()
|
function initDatePickers()
|
||||||
{
|
{
|
||||||
$('#nextrunselector').datetimepicker({format: 'L LTS'});
|
$('#nextrunselector').datetimepicker({format: 'DD/MM/YYYY HH:mm:ss'});
|
||||||
$('#lastrunselector').datetimepicker({format: 'L LTS'});
|
$('#lastrunselector').datetimepicker({format: 'DD/MM/YYYY HH:mm:ss'});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initCronType()
|
function initCronType()
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
.text-end {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
|
@ -26,6 +26,27 @@ class JobController extends Controller
|
||||||
$job = $jobRepo->getJob($id);
|
$job = $jobRepo->getJob($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function editAction($id)
|
||||||
|
{
|
||||||
|
if($this->getRequest()->getMethod() == 'GET') {
|
||||||
|
$jobRepo = new Job($this->getDbCon());
|
||||||
|
$job = $jobRepo->getJob($id, true);
|
||||||
|
return $this->render('job/edit.html.twig', $job);
|
||||||
|
} elseif($this->getRequest()->getMethod() == 'POST') {
|
||||||
|
$allValues = $this->getRequest()->request->all();
|
||||||
|
$jobRepo = new Job($this->getDbCon());
|
||||||
|
|
||||||
|
try {
|
||||||
|
$joboutput = $jobRepo->editJob($id, $allValues);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
$this->addFlash('danger', $e->getMessage());
|
||||||
|
return new RedirectResponse($this->generateRoute('job_edit', ['id' => $allValues['id']]));
|
||||||
|
}
|
||||||
|
$this->addFlash('success', $joboutput['message']);
|
||||||
|
return new RedirectResponse($this->generateRoute('job_index'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function addAction()
|
public function addAction()
|
||||||
{
|
{
|
||||||
if($this->getRequest()->getMethod() == 'GET') {
|
if($this->getRequest()->getMethod() == 'GET') {
|
||||||
|
@ -33,14 +54,15 @@ class JobController extends Controller
|
||||||
} elseif ($this->getRequest()->getMethod() == 'POST') {
|
} elseif ($this->getRequest()->getMethod() == 'POST') {
|
||||||
$allValues = $this->getRequest()->request->all();
|
$allValues = $this->getRequest()->request->all();
|
||||||
$jobRepo = new Job($this->getDbCon());
|
$jobRepo = new Job($this->getDbCon());
|
||||||
|
try {
|
||||||
$joboutput = $jobRepo->addJob($allValues);
|
$joboutput = $jobRepo->addJob($allValues);
|
||||||
if($joboutput['success']) {
|
} catch (\InvalidArgumentException $e) {
|
||||||
$this->addFlash('success', $joboutput['message']);
|
$this->addFlash('danger', $e->getMessage());
|
||||||
return new RedirectResponse($this->generateRoute('job_index'));
|
|
||||||
} else {
|
|
||||||
$this->addFlash('danger', $joboutput['message']);
|
|
||||||
return new RedirectResponse($this->generateRoute('job_add'));
|
return new RedirectResponse($this->generateRoute('job_add'));
|
||||||
}
|
}
|
||||||
|
$this->addFlash('success', $joboutput['message']);
|
||||||
|
return new RedirectResponse($this->generateRoute('job_index'));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return new Response('Not implemented yet', Response::HTTP_TOO_EARLY);
|
return new Response('Not implemented yet', Response::HTTP_TOO_EARLY);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,30 +35,62 @@ class Job
|
||||||
empty($values['interval']) ||
|
empty($values['interval']) ||
|
||||||
empty($values['nextrun'])
|
empty($values['nextrun'])
|
||||||
) {
|
) {
|
||||||
return ['success' => false, 'message' => 'Some fields are empty'];
|
throw new \InvalidArgumentException('Some fields are empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = $this->prepareJob($values);
|
||||||
|
$data['data'] = json_encode($data['data']);
|
||||||
|
$addJobSql = "INSERT INTO job(name, data, interval, nextrun, lastrun) VALUES (:name, :data, :interval, :nextrun, :lastrun)";
|
||||||
|
|
||||||
|
$addJobStmt = $this->dbcon->prepare($addJobSql);
|
||||||
|
$addJobStmt->executeQuery([':name' => $data['name'], ':data' => $data['data'], ':interval' => $data['interval'], ':nextrun' => $data['nextrun'], ':lastrun' => $data['lastrun'], ]);
|
||||||
|
|
||||||
|
return ['success' => true, 'message' => 'Cronjob succesfully added'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function editJob(int $id, array $values)
|
||||||
|
{
|
||||||
|
if(empty($values['crontype']) ||
|
||||||
|
empty($values['name']) ||
|
||||||
|
empty($values['interval']) ||
|
||||||
|
empty($values['nextrun'])
|
||||||
|
) {
|
||||||
|
throw new \InvalidArgumentException('Some fields are empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->prepareJob($values);
|
||||||
|
$data['data'] = json_encode($data['data']);
|
||||||
|
$editJobSql = "UPDATE job set name = :name, data = :data, interval = :interval, nextrun = :nextrun, lastrun = :lastrun WHERE id = :id";
|
||||||
|
|
||||||
|
$editJobStmt = $this->dbcon->prepare($editJobSql);
|
||||||
|
$editJobStmt->executeQuery([':name' => $data['name'], ':data' => $data['data'], ':interval' => $data['interval'], ':nextrun' => $data['nextrun'], ':lastrun' => $data['lastrun'],':id' => $id ]);
|
||||||
|
|
||||||
|
return ['success' => true, 'message' => 'Cronjob succesfully edited'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareJob(array $values): array
|
||||||
|
{
|
||||||
if(empty($values['lastrun'])) {
|
if(empty($values['lastrun'])) {
|
||||||
$values['lastrun'] = NULL;
|
$values['lastrun'] = NULL;
|
||||||
} else {
|
} else {
|
||||||
$values['lastrun'] = DateTime::createFromFormat('m/d/Y g:i:s A',$values['lastrun'])->getTimestamp();
|
$values['lastrun'] = DateTime::createFromFormat('m/d/Y H:i:s',$values['lastrun'])->getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
$values['nextrun'] = DateTime::createFromFormat('m/d/Y g:i:s A', $values['nextrun'])->getTimestamp();
|
$values['nextrun'] = DateTime::createFromFormat('m/d/Y H:i:s', $values['nextrun'])->getTimestamp();
|
||||||
$data['crontype'] = $values['crontype'];
|
$values['data']['crontype'] = $values['crontype'];
|
||||||
$data['hosttype'] = $values['hosttype'];
|
$values['data']['hosttype'] = $values['hosttype'];
|
||||||
$data['containertype'] = $values['containertype'];
|
$values['data']['containertype'] = $values['containertype'];
|
||||||
|
|
||||||
switch($data['crontype'])
|
switch($values['data']['crontype'])
|
||||||
{
|
{
|
||||||
case 'command':
|
case 'command':
|
||||||
$data['command'] = $values['command'];
|
$values['data']['command'] = $values['command'];
|
||||||
$data['response'] = $values['response'];
|
$values['data']['response'] = $values['response'];
|
||||||
break;
|
break;
|
||||||
case 'reboot':
|
case 'reboot':
|
||||||
$data['reboot-command'] = $values['reboot-command'];
|
$values['data']['reboot-command'] = $values['reboot-command'];
|
||||||
$data['getservices-command'] = $values['getservices-command'];
|
$values['data']['getservices-command'] = $values['getservices-command'];
|
||||||
$data['reboot-duration'] = $values['reboot-duration'];
|
$values['data']['reboot-duration'] = $values['reboot-duration'];
|
||||||
if(!empty($values['reboot-delay'])) {
|
if(!empty($values['reboot-delay'])) {
|
||||||
$newsecretkey = count($values['var-value']);
|
$newsecretkey = count($values['var-value']);
|
||||||
$values['var-id'][$newsecretkey] = 'reboot-delay';
|
$values['var-id'][$newsecretkey] = 'reboot-delay';
|
||||||
|
@ -73,11 +105,11 @@ class Job
|
||||||
break;
|
break;
|
||||||
case 'http':
|
case 'http':
|
||||||
$parsedUrl = parse_url($values['url']);
|
$parsedUrl = parse_url($values['url']);
|
||||||
$data['url'] = $values['url'];
|
$values['data']['url'] = $values['url'];
|
||||||
$data['response'] = $values['response'];
|
$values['data']['response'] = $values['response'];
|
||||||
$data['basicauth-username'] = $values['basicauth-username'];
|
$values['data']['basicauth-username'] = $values['basicauth-username'];
|
||||||
if(empty($parsedUrl['host'])) {
|
if(empty($parsedUrl['host'])) {
|
||||||
return ['success' => false, 'message' => 'Some data was invalid'];
|
throw new \InvalidArgumentException('Some data was invalid');
|
||||||
}
|
}
|
||||||
if(!empty($values['basicauth-password'])) {
|
if(!empty($values['basicauth-password'])) {
|
||||||
$newsecretkey = count($values['var-value']);
|
$newsecretkey = count($values['var-value']);
|
||||||
|
@ -85,17 +117,17 @@ class Job
|
||||||
$values['var-issecret'][$newsecretkey] = true;
|
$values['var-issecret'][$newsecretkey] = true;
|
||||||
$values['var-value'][$newsecretkey] = $values['basicauth-password'];
|
$values['var-value'][$newsecretkey] = $values['basicauth-password'];
|
||||||
}
|
}
|
||||||
$data['host'] = $parsedUrl['host'];
|
$values['data']['host'] = $parsedUrl['host'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch($data['hosttype']) {
|
switch($values['data']['hosttype']) {
|
||||||
case 'local':
|
case 'local':
|
||||||
$data['host'] = 'localhost';
|
$values['data']['host'] = 'localhost';
|
||||||
break;
|
break;
|
||||||
case 'ssh':
|
case 'ssh':
|
||||||
$data['host'] = $values['host'];
|
$values['data']['host'] = $values['host'];
|
||||||
$data['user'] = $values['user'];
|
$values['data']['user'] = $values['user'];
|
||||||
if(!empty($values['privkey-password'])) {
|
if(!empty($values['privkey-password'])) {
|
||||||
$newsecretkey = count($values['var-value']);
|
$newsecretkey = count($values['var-value']);
|
||||||
$values['var-id'][$newsecretkey] = 'privkey-password';
|
$values['var-id'][$newsecretkey] = 'privkey-password';
|
||||||
|
@ -112,10 +144,10 @@ class Job
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch($data['containertype']) {
|
switch($values['data']['containertype']) {
|
||||||
case 'docker':
|
case 'docker':
|
||||||
$data['service'] = $values['service'];
|
$values['data']['service'] = $values['service'];
|
||||||
$data['user'] = $values['user'];
|
$values['data']['user'] = $values['user'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,23 +155,16 @@ class Job
|
||||||
foreach($values['var-value'] as $key => $name) {
|
foreach($values['var-value'] as $key => $name) {
|
||||||
if(!empty($name)) {
|
if(!empty($name)) {
|
||||||
if(isset($values['var-issecret'][$key]) && $values['var-issecret'][$key] != false) {
|
if(isset($values['var-issecret'][$key]) && $values['var-issecret'][$key] != false) {
|
||||||
$data['vars'][$values['var-id'][$key]]['issecret'] = true;
|
$values['data']['vars'][$values['var-id'][$key]]['issecret'] = true;
|
||||||
$data['vars'][$values['var-id'][$key]]['value'] = base64_encode(Secret::encrypt($values['var-value'][$key]));
|
$values['data']['vars'][$values['var-id'][$key]]['value'] = base64_encode(Secret::encrypt($values['var-value'][$key]));
|
||||||
} else {
|
} else {
|
||||||
$data['vars'][$values['var-id'][$key]]['issecret'] = false;
|
$values['data']['vars'][$values['var-id'][$key]]['issecret'] = false;
|
||||||
$data['vars'][$values['var-id'][$key]]['value'] = $values['var-value'][$key];
|
$values['data']['vars'][$values['var-id'][$key]]['value'] = $values['var-value'][$key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return $values;
|
||||||
$data = json_encode($data);
|
|
||||||
$addJobSql = "INSERT INTO job(name, data, interval, nextrun, lastrun) VALUES (:name, :data, :interval, :nextrun, :lastrun)";
|
|
||||||
|
|
||||||
$addJobStmt = $this->dbcon->prepare($addJobSql);
|
|
||||||
$addJobStmt->executeQuery([':name' => $values['name'], ':data' => $data, ':interval' => $values['interval'], ':nextrun' => $values['nextrun'], ':lastrun' => $values['lastrun'], ]);
|
|
||||||
|
|
||||||
return ['success' => true, 'message' => 'Cronjob succesfully added'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getJob(int $id, bool $withSecrets = false) {
|
public function getJob(int $id, bool $withSecrets = false) {
|
||||||
|
@ -148,6 +173,7 @@ class Job
|
||||||
$jobRslt = $jobStmt->execute([':id' => $id])->fetchAssociative();
|
$jobRslt = $jobStmt->execute([':id' => $id])->fetchAssociative();
|
||||||
|
|
||||||
$jobRslt['data'] = json_decode($jobRslt['data'], true);
|
$jobRslt['data'] = json_decode($jobRslt['data'], true);
|
||||||
|
|
||||||
if(!empty($jobRslt['data']['vars'])) {
|
if(!empty($jobRslt['data']['vars'])) {
|
||||||
foreach ($jobRslt['data']['vars'] as $key => &$value) {
|
foreach ($jobRslt['data']['vars'] as $key => &$value) {
|
||||||
if ($value['issecret']) {
|
if ($value['issecret']) {
|
||||||
|
@ -156,6 +182,16 @@ class Job
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch($jobRslt['data']['crontype']) {
|
||||||
|
case 'http':
|
||||||
|
if(isset($jobRslt['data']['vars']['basicauth-password']['value'])) {
|
||||||
|
$jobRslt['data']['basicauth-password'] = $jobRslt['data']['vars']['basicauth-password']['value'];
|
||||||
|
unset($jobRslt['data']['vars']['basicauth-password']);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if($jobRslt['data']['crontype'] == 'http') {
|
||||||
|
}
|
||||||
return $jobRslt;
|
return $jobRslt;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,14 +18,14 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row py-3">
|
<div class="row py-3">
|
||||||
<div class="col-xs-12 col-sm-12">
|
<div class="col-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>Webcron management</h1>
|
<h1>Webcron management</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row py-3">
|
<div class="row py-3">
|
||||||
<div class="col-xs-12 col-sm-2">
|
<div class="col-12 col-lg-3">
|
||||||
<ul class="nav flex-column">
|
<ul class="nav flex-column">
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ path('job_index') }}">Overview</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{ path('job_index') }}">Overview</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ path('job_add') }}">Add a new cronjob</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{ path('job_add') }}">Add a new cronjob</a></li>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ path('logout') }}">Logout</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{ path('logout') }}">Logout</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-10">
|
<div class="col-12 col-lg-9">
|
||||||
{{ include('flashes.html.twig') }}
|
{{ include('flashes.html.twig') }}
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<h3>Job details</h3>
|
<h3>Job details</h3>
|
||||||
<div class="mb-3 btn-group">
|
<div class="mb-3 btn-group">
|
||||||
<div class="dropdown croncategory-group crontype-group">
|
<div class="dropdown croncategory-group crontype-group">
|
||||||
<button class="btn btn-outline-primary dropdown-toggle" data-default-text="" type="button" id="crontypeButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="crontypeButton" data-default-text="" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Job type
|
Job type
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu" aria-labelledby="crontypeButton">
|
<div class="dropdown-menu" aria-labelledby="crontypeButton">
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dropdown croncategory-group hidden hosttype-group">
|
<div class="dropdown croncategory-group hidden hosttype-group">
|
||||||
<button class="btn btn-outline-primary dropdown-toggle" data-default-text="" type="button" id="hosttypeButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="hosttypeButton" data-default-text="" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Host type
|
Host type
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu" aria-labelledby="hosttypeButton">
|
<div class="dropdown-menu" aria-labelledby="hosttypeButton">
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dropdown croncategory-group hidden containertype-group">
|
<div class="dropdown croncategory-group hidden containertype-group">
|
||||||
<button class="btn btn-outline-primary dropdown-toggle" data-default-text="" type="button" id="containertypeButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="containertypeButton" data-default-text="" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
Container
|
Container
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu" aria-labelledby="containertypeButton">
|
<div class="dropdown-menu" aria-labelledby="containertypeButton">
|
||||||
|
@ -182,6 +182,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Variables</h3>
|
<h3>Variables</h3>
|
||||||
|
|
||||||
<div class="vars mb-3">
|
<div class="vars mb-3">
|
||||||
<div class="input-group var-group hidden">
|
<div class="input-group var-group hidden">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
|
|
253
templates/job/edit.html.twig
Normal file
253
templates/job/edit.html.twig
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
{% extends "base.html.twig" %}
|
||||||
|
{% block title %}Add job{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h2>Add a cronjob</h2>
|
||||||
|
<form method="post" class="form-horizontal" enctype="multipart/form-data" action="{{ path('job_edit', { id : id }) }}">
|
||||||
|
|
||||||
|
<h3>General info</h3>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
<input type="text" name="name" class="form-control" id="name" placeholder="System update" value="{{ name }}">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="name">Interval (in seconds)</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="dropdown input-group-prepend">
|
||||||
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="intervalButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
Patterns
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="intervalButton">
|
||||||
|
<a class="dropdown-item intervalpattern-item" href="#" data-time="60">Every minute</a>
|
||||||
|
<a class="dropdown-item intervalpattern-item" href="#" data-time="3600">Every hour</a>
|
||||||
|
<a class="dropdown-item intervalpattern-item" href="#" data-time="86400">Every day</a>
|
||||||
|
<a class="dropdown-item intervalpattern-item" href="#" data-time="604800">Every week</a>
|
||||||
|
<a class="dropdown-item intervalpattern-item" href="#" data-time="2419200">Every 4 weeks</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="number" class="form-control" id="interval" name="interval" value="{{ interval }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="nextrun">Next run</label>
|
||||||
|
<input type="text" autocomplete="off" id="nextrunselector" class="form-control datetimepicker-input" data-target="#nextrunselector" data-toggle="datetimepicker" name="nextrun" value="{{ nextrun | date("d/m/Y H:i:s")}}">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="lastrun">Last run</label>
|
||||||
|
<input type="text" autocomplete="off" id="lastrunselector" class="form-control datetimepicker-input" data-target="#lastrunselector" data-toggle="datetimepicker" name="lastrun" value="{{ lastrun | date("d/m/Y H:i:s")}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Job details</h3>
|
||||||
|
<div class="mb-3 btn-group">
|
||||||
|
<div class="dropdown croncategory-group crontype-group{% if data.crontype != 'http' %} btn-group{% endif %}">
|
||||||
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="crontypeButton" data-default-text="Job type" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
{% if data.crontype == 'command' %}
|
||||||
|
Command
|
||||||
|
{% elseif data.crontype == 'reboot' %}
|
||||||
|
Reboot
|
||||||
|
{% elseif data.crontype == 'http' %}
|
||||||
|
Http request
|
||||||
|
{% endif %}
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="crontypeButton">
|
||||||
|
<a class="dropdown-item crontype-item" href="#" data-type="command">Command</a>
|
||||||
|
<a class="dropdown-item crontype-item" href="#" data-type="reboot">Reboot</a>
|
||||||
|
<a class="dropdown-item crontype-item" href="#" data-type="http">Http request</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dropdown croncategory-group hosttype-group{% if data.crontype != 'http' %} btn-group{% else %} hidden{% endif %}">
|
||||||
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="hosttypeButton" data-default-text="Host type" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
{% if data.hosttype == 'local' %}
|
||||||
|
Local
|
||||||
|
{% elseif data.hosttype == 'ssh' %}
|
||||||
|
SSH
|
||||||
|
{% endif %}
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="hosttypeButton">
|
||||||
|
<a class="dropdown-item hosttype-item" href="#" data-type="local">Local</a>
|
||||||
|
<a class="dropdown-item hosttype-item" href="#" data-type="ssh">SSH</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="dropdown croncategory-group containertype-group{% if data.crontype != 'http' %} btn-group{% else %} hidden{% endif %}">
|
||||||
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" id="containertypeButton" data-default-text="" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
{% if data.containertype == 'none' %}
|
||||||
|
None
|
||||||
|
{% elseif data.containertype == 'docker' %}
|
||||||
|
Docker
|
||||||
|
{% endif %}
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="containertypeButton">
|
||||||
|
<a class="dropdown-item containertype-item" href="#" data-type="none">None</a>
|
||||||
|
<a class="dropdown-item containertype-item" href="#" data-type="docker">Docker</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="crontype-command crontype-inputs croncategory-inputs{% if data.crontype != 'command' %} hidden{% endif %}">
|
||||||
|
<h4>Command details</h4>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="command">Command</label>
|
||||||
|
<input type="text" name="command" class="form-control" id="command" placeholder="sudo apt update" value="{% if data.command is not empty %}{{ data.command }}{% endif %}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="response">Expected exit code</label>
|
||||||
|
<input type="text" name="response" class="form-control" id="response" placeholder="0" value="{% if data.response is not empty %}{{ data.response }}{% endif %}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="crontype-reboot crontype-inputs croncategory-inputs{% if data.crontype != 'reboot' %} hidden{% endif %}">
|
||||||
|
<h4>Reboot job details</h4>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="reboot-command">Reboot command</label>
|
||||||
|
<input type="text" name="reboot-command" class="form-control" id="command" placeholder="systemctl reboot" value="{% if attribute(data, 'reboot-command') is not empty %}{{ attribute(data, 'reboot-command') }}{% endif %}">
|
||||||
|
<small id="reboot-command-help" class="form-text text-muted">Use {reboot-delay} or {reboot-delay-secs} to add the delay in your command</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="getservices-command">Get services command</label>
|
||||||
|
<input type="text" name="getservices-command" class="form-control" id="command" placeholder="systemctl list-units" value="{% if attribute(data, 'getservices-command') is not empty %}{{ attribute(data, 'getservices-command') }}{% endif %}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="reboot-delay">Reboot delay (in minutes)</label>
|
||||||
|
<input type="number" name="reboot-delay" class="form-control" placeholder="5" value="{% if attribute(data.vars, 'reboot-delay').value is not empty %}{{ attribute(data.vars, 'reboot-delay').value }}{% endif %}">
|
||||||
|
<small id="reboot-delay-help" class="form-text text-muted">Delay between triggering reboot and actual reboot</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="reboot-duration">Reboot duration (in minutes)</label>
|
||||||
|
<input type="number" name="reboot-duration" class="form-control" placeholder="10" value="{% if attribute(data, 'reboot-duration') is not empty %}{{ attribute(data, 'reboot-duration') }}{% endif %}">
|
||||||
|
<small id="reboot-duration-help" class="form-text text-muted">The amount of time the system takes to actually reboot</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="crontype-http crontype-inputs croncategory-inputs{% if data.crontype != 'http' %} hidden{% endif %}">
|
||||||
|
<h4>HTTP request details</h4>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="url">Url</label>
|
||||||
|
<input type="text" name="url" class="form-control" id="url" placeholder="https://scripts.example.com/" value="{% if data.url is not empty %}{{ data.url }}{% endif %}">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="basicauth-username">Username for Basic-Auth</label>
|
||||||
|
<input type="text" name="basicauth-username" class="form-control" id="basicauth-username" placeholder="www-data" value="{% if attribute(data, 'basicauth-username') is not empty %}{{ attribute(data, 'basicauth-username') }}{% endif %}">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="basicauth-password">Password for Basic-Auth</label>
|
||||||
|
<input type="password" name="basicauth-password" class="form-control" placeholder="correct horse battery staple" value="{% if attribute(data, 'basicauth-password') is not empty %}{{ attribute(data, 'basicauth-password') }}{% endif %}">
|
||||||
|
<small id="basicauth-password-help" class="form-text text-muted">This field is being saved as a secret</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="response">Expected response status code</label>
|
||||||
|
<input type="text" name="response" class="form-control" id="response" placeholder="200" value="{% if attribute(data, 'response') is not empty %}{{ attribute(data, 'response') }}{% endif %}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hosttype-local hosttype-inputs croncategory-inputs{% if data.hosttype != 'local' %} hidden{% endif %}">
|
||||||
|
<h4>Localhost details</h4>
|
||||||
|
<h5>No options</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hosttype-ssh hosttype-inputs croncategory-inputs{% if data.hosttype != 'ssh' %} hidden{% endif %}">
|
||||||
|
<h4>SSH host details</h4>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="host">Hostname</label>
|
||||||
|
<input type="text" name="host" class="form-control" id="host" placeholder="ssh.abc.xyz">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="user">Username</label>
|
||||||
|
<input type="text" name="user" class="form-control" id="user" placeholder="larry">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="privkey">Private key</label>
|
||||||
|
<div class="custom-file">
|
||||||
|
<input type="file" class="custom-file-input" id="privkey" name="privkey">
|
||||||
|
<label class="custom-file-label" for="privkey">Choose file</label>
|
||||||
|
</div>
|
||||||
|
<small id="custom-file-help" class="form-text text-muted">This file is being saved as a secret</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="privkey-password">Password for private key</label>
|
||||||
|
<input type="password" name="privkey-password" class="form-control" placeholder="correct horse battery staple">
|
||||||
|
<small id="privkey-password-help" class="form-text text-muted">If private key is empty this field is being used as ssh-password</small>
|
||||||
|
<small id="privkey-password-help-2" class="form-text text-muted">This field is being saved as a secret</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="containertype-none containertype-inputs croncategory-inputs{% if data.containertype != 'none' %} hidden{% endif %}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="containertype-docker containertype-inputs croncategory-inputs{% if data.containertype != 'docker' %} hidden{% endif %}">
|
||||||
|
<h4>Docker container details</h4>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="service">Service</label>
|
||||||
|
<input type="text" name="service" class="form-control" id="service" placeholder="mysql">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="user">Username</label>
|
||||||
|
<input type="text" name="user" class="form-control" id="user" placeholder="larry">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>Variables</h3>
|
||||||
|
|
||||||
|
<div class="vars mb-3">
|
||||||
|
<div class="input-group var-group hidden">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<div class="input-group-text border-right-0">
|
||||||
|
<input type="checkbox" name="var-issecret[0]" class="var-issecret" placeholder="value" value="true">
|
||||||
|
</div>
|
||||||
|
<span class="input-group-text border-left-0">Secret</span>
|
||||||
|
</div>
|
||||||
|
<input type="text" name="var-id[0]" class="form-control var-id" placeholder="name">
|
||||||
|
<input type="text" name="var-value[0]" class="form-control var-value" placeholder="value">
|
||||||
|
</div>
|
||||||
|
{% set key = 1 %}
|
||||||
|
{% for id,var in data.vars %}
|
||||||
|
<div class="input-group var-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<div class="input-group-text border-right-0">
|
||||||
|
<input type="checkbox" name="var-issecret[{{ key }}]" class="var-issecret" placeholder="value" value="true"{% if var.issecret %} checked{% endif %}>
|
||||||
|
</div>
|
||||||
|
<span class="input-group-text border-left-0">Secret</span>
|
||||||
|
</div>
|
||||||
|
<input type="text" name="var-id[{{ key }}]" class="form-control var-id" placeholder="name" value="{{ id }}">
|
||||||
|
<input type="{% if var.issecret %}password{% else %}text{% endif %}" name="var-value[{{ key }}]" class="form-control var-value" placeholder="value" value="{{ var.value }}">
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="vars-description mb-3 hidden">
|
||||||
|
<p>
|
||||||
|
You can add variables by using {variable-name} in job details
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<a href="#" class="btn btn-outline-primary addvar-btn">Add variable</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" name="crontype" class="crontype" value="{{ data.crontype }}">
|
||||||
|
<input type="hidden" name="hosttype" class="hosttype" value="{{ data.hosttype }}">
|
||||||
|
<input type="hidden" name="containertype" class="containertype" value="{{ data.containertype }}">
|
||||||
|
<button type="submit" class="btn btn-outline-primary">Submit</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrastyles %}
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tempusdominus-bootstrap-4/5.39.0/css/tempusdominus-bootstrap-4.min.css" integrity="sha512-3JRrEUwaCkFUBLK1N8HehwQgu8e23jTH4np5NHOmQOobuC4ROQxFwFgBLTnhcnQRMs84muMh0PnnwXlPq5MGjg==" crossorigin="anonymous" />
|
||||||
|
<link rel="stylesheet" href="/resources/job/add.css" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extrascripts %}
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous"></script>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/tempusdominus-bootstrap-4/5.39.0/js/tempusdominus-bootstrap-4.min.js" integrity="sha512-k6/Bkb8Fxf/c1Tkyl39yJwcOZ1P4cRrJu77p83zJjN2Z55prbFHxPs9vN7q3l3+tSMGPDdoH51AEU8Vgo1cgAA==" crossorigin="anonymous"></script>
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bs-custom-file-input/1.3.4/bs-custom-file-input.min.js" integrity="sha512-91BoXI7UENvgjyH31ug0ga7o1Ov41tOzbMM3+RPqFVohn1UbVcjL/f5sl6YSOFfaJp+rF+/IEbOOEwtBONMz+w==" crossorigin="anonymous"></script>
|
||||||
|
<script type="text/javascript" src="/resources/job/add.js"></script>
|
||||||
|
{% endblock %}
|
|
@ -3,30 +3,34 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Overview of your cronjobs</h2>
|
<h2>Overview of your cronjobs</h2>
|
||||||
|
|
||||||
<table class="table">
|
<table class="table table-md-striped">
|
||||||
<tr>
|
<thead>
|
||||||
|
<tr class="d-none d-md-table-row">
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Host</th>
|
<th>Host</th>
|
||||||
<th>Delay</th>
|
<th>Delay</th>
|
||||||
<th>Next run</th>
|
<th>Next run</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
{% for job in jobs %}
|
{% for job in jobs %}
|
||||||
<tr{% if(job.norun == true) %} class="norun"{% endif %}>
|
<tr{% if(job.norun == true) %} class="norun"{% endif %}>
|
||||||
<td>{{ job.name }}</td>
|
<td class="d-block d-md-table-cell">{{ job.name }}</td>
|
||||||
<td>{{ job.data.host }}</td>
|
<td class="d-block d-md-table-cell">{{ job.data.host }}</td>
|
||||||
<td>{{ job.interval | interval }}</td>
|
<td class="d-block d-md-table-cell">{{ job.interval | interval }}</td>
|
||||||
<td>{{ job.nextrun | date("d/m/Y H:i:s") }}</td>
|
<td class="d-block d-md-table-cell">{{ job.nextrun | date("d/m/Y H:i:s") }}</td>
|
||||||
<td class="text-end">
|
<td class="text-md-right d-block d-md-table-cell">
|
||||||
<a href="#" data-id="{{ job.id }}" class="runcron btn btn-outline-primary"><i class="fa fa-play" aria-hidden="true"></i></a>
|
<a href="#" data-id="{{ job.id }}" class="runcron btn btn-outline-primary"><i class="fa fa-play" aria-hidden="true"></i></a>
|
||||||
<a href="{{ path('job_view', {'id': job.id}) }}" class="btn btn-outline-primary"><i class="fa fa-search" aria-hidden="true"></i></a>
|
<a href="{{ path('job_view', {'id': job.id}) }}" class="btn btn-outline-primary"><i class="fa fa-search" aria-hidden="true"></i></a>
|
||||||
<a href="editjob.php?jobID={{ job.id }}" class="btn btn-outline-primary"><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a>
|
<a href="{{ path('job_edit', {'id': job.id}) }}" class="btn btn-outline-primary"><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a>
|
||||||
<a onclick="return confirm('Are you sure you want to delete this job?')" href="overview.php?id={{ job.id }}&action=delete" class="btn btn-outline-primary"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
|
<a onclick="return confirm('Are you sure you want to delete this job?')" href="overview.php?id={{ job.id }}&action=delete" class="btn btn-outline-primary"><i class="fa fa-trash-o" aria-hidden="true"></i></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</tbody>
|
||||||
<div id="resultmodal" class="modal fade" role="dialog">
|
</table>
|
||||||
|
<div id="resultmodal" class="modal fade" role="dialog">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
@ -40,10 +44,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id='ajax_loader' style="position: fixed; left: 50%; top: 50%; display: none;">
|
<div id='ajax_loader' style="position: fixed; left: 50%; top: 50%; display: none;">
|
||||||
<img src="/public/images/ajax-loader.gif" alt="loading">
|
<img src="/public/images/ajax-loader.gif" alt="loading">
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extrastyles %}
|
{% block extrastyles %}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user