Make more AJAXy
This commit is contained in:
parent
c76697f846
commit
0de4709c30
9 changed files with 105 additions and 19 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
__pycache__
|
__pycache__
|
||||||
*.pyc
|
*.pyc
|
||||||
static
|
static/static_root
|
||||||
|
|
33
manager/migrations/0007_auto_20181128_1427.py
Normal file
33
manager/migrations/0007_auto_20181128_1427.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Generated by Django 2.1.3 on 2018-11-28 14:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('manager', '0006_auto_20181126_0849'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='reboot',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Trigger Reboot'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='network',
|
||||||
|
name='extip',
|
||||||
|
field=models.CharField(max_length=15, verbose_name='External/Public IP'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='network',
|
||||||
|
name='intip',
|
||||||
|
field=models.CharField(max_length=15, verbose_name='Internal/Private IP'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='organization',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(max_length=300, verbose_name='Organization Name'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -28,6 +28,7 @@ class Device(models.Model):
|
||||||
curip = models.CharField("Current IP Address", max_length=15, blank=True, null=True)
|
curip = models.CharField("Current IP Address", max_length=15, blank=True, null=True)
|
||||||
lasttime = models.DateTimeField("Last Received Heartbeat", blank=True, null=True)
|
lasttime = models.DateTimeField("Last Received Heartbeat", blank=True, null=True)
|
||||||
secret = models.CharField("Secret", default=getRandom, max_length=128)
|
secret = models.CharField("Secret", default=getRandom, max_length=128)
|
||||||
|
reboot = models.BooleanField("Trigger Reboot", default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s%s" % (self.serial, " (%s)" % self.curip if self.curip else "")
|
return "%s%s" % (self.serial, " (%s)" % self.curip if self.curip else "")
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
<title>VPN360 Device Administration</title>
|
<title>VPN360 Device Administration</title>
|
||||||
|
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
|
||||||
<!-- link href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.12/css/dataTables.bootstrap4.min.css" rel="stylesheet"/ --!>
|
<!-- link href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.12/css/dataTables.bootstrap4.min.css" rel="stylesheet"/ --!>
|
||||||
|
@ -17,8 +19,7 @@
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.bundle.min.js"></script>
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.bundle.min.js"></script>
|
||||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.12/js/jquery.dataTables.min.js"></script>
|
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.12/js/jquery.dataTables.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.13/js/dataTables.bootstrap4.min.js"></script> -->
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.13/js/dataTables.bootstrap4.min.js"></script> --!>
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,11 @@
|
||||||
<option {% if choice.intip == device.network.intip %} selected {% endif %} value="{{ choice.intip }}">{{ choice.intip}} ({{ choice.extip }})</option>
|
<option {% if choice.intip == device.network.intip %} selected {% endif %} value="{{ choice.intip }}">{{ choice.intip}} ({{ choice.extip }})</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<small id="subnetHelp" class="form-text text-muted">A network change will require a (manual) reboot of the device to be applied.</small>
|
<small id="subnetHelp" class="form-text text-muted">A network change will require a reboot of the device to be applied.</small>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" value="True" {% if device.reboot %} checked {% endif %} id="reboot" name="reboot">
|
||||||
|
<label class="form-check-label" for="reboot">Reboot device immediately </label>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-success">Apply Changes</button>
|
<button type="submit" class="btn btn-success">Apply Changes</button>
|
||||||
<a class="btn btn-danger" href="/" role="button">Cancel</a>
|
<a class="btn btn-danger" href="/" role="button">Cancel</a>
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
|
|
||||||
{% for device in devices %}
|
{% for device in devices %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ device.serial }}</td>
|
<td><div style="display: inline; color: grey; font-weight: bold;" id="{{ device.id }}-indicator">⬤</div> {{ device.serial }}</td>
|
||||||
<td>{% if device.name %}{{ device.name }}{% endif %}</td>
|
<td>{% if device.name %}{{ device.name }}{% endif %}</td>
|
||||||
<td>{{ device.network }}</td>
|
<td>{{ device.network }}</td>
|
||||||
<td>{% if device.curip %}{{ device.curip }} (at {{ device.lasttime }}){% endif %}</td>
|
<td><div style="display:inline" id="{{ device.id }}-ip">{% if device.curip %}{{ device.curip }} (at {{ device.lasttime }}){% endif %}</div></td>
|
||||||
<td>{{ device.secret }}</td>
|
<td>{{ device.secret }}</td>
|
||||||
<td><a href="/devices/{{ device.id }}/edit"><i class="fas fa-edit"></i></a></td>
|
<td><a href="/devices/{{ device.id }}/edit"><i class="fas fa-edit"></i></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -32,10 +32,17 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="/js/devices.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/* $(document).ready(function() {
|
/*$(document).ready(function() {
|
||||||
$('#table').DataTable();
|
$('#table').DataTable();
|
||||||
}); */
|
});*/
|
||||||
|
|
||||||
|
{% for device in devices %}
|
||||||
|
updateStatus({{ device.id }});
|
||||||
|
setInterval(updateStatus, 3000, {{ device.id }});
|
||||||
|
{% endfor %}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,34 +21,42 @@ def heartbeat(request):
|
||||||
device.curip = request.POST.get("ip", "")
|
device.curip = request.POST.get("ip", "")
|
||||||
device.lasttime = timezone.now()
|
device.lasttime = timezone.now()
|
||||||
device.save()
|
device.save()
|
||||||
return HttpResponse("")
|
return HttpResponse("reboot" if device.reboot else "")
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def hosts(request):
|
def hosts(request):
|
||||||
device = get_object_or_404(Device, secret=request.POST.get("secret", ""))
|
device = get_object_or_404(Device, secret=request.POST.get("secret", ""))
|
||||||
|
device.reboot = False
|
||||||
|
device.save()
|
||||||
return render(request, "manager/hosts", {"device": device})
|
return render(request, "manager/hosts", {"device": device})
|
||||||
|
|
||||||
def ping(request, device_id):
|
def ping(request, device_id):
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
device = None
|
device = None
|
||||||
|
ajax = '{\n "status": '
|
||||||
|
|
||||||
for organization in Organization.objects.filter(users=request.user):
|
for organization in Organization.objects.filter(users=request.user):
|
||||||
device = device or Device.objects.filter(id=device_id, organization=organization)
|
device = device or Device.objects.filter(id=device_id, organization=organization)
|
||||||
|
|
||||||
if not device:
|
if not device:
|
||||||
return HttpResponse("-1")
|
ajax += "-1"
|
||||||
|
|
||||||
try:
|
else:
|
||||||
socket.inet_aton(device[0].curip)
|
try:
|
||||||
return HttpResponse(str(int(not os.WEXITSTATUS(os.system("ping -c1 -w1 " + device[0].curip + " > /dev/null 2>&1"))))) # This monster is not long enough yet.
|
socket.inet_aton(device[0].curip)
|
||||||
|
ajax += str(int(not os.WEXITSTATUS(os.system("ping -c1 -w1 " + device[0].curip + " > /dev/null 2>&1")))) # This monster is not long enough yet.
|
||||||
|
ajax += ',\n "ip": "%s"' % device[0].curip
|
||||||
|
ajax += ',\n "time": "%s"' % device[0].lasttime
|
||||||
|
|
||||||
except:
|
except:
|
||||||
return HttpResponse("-3")
|
ajax += "-3"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return HttpResponse("-2")
|
ajax += "-2"
|
||||||
|
|
||||||
|
ajax += "\n}"
|
||||||
|
return HttpResponse(ajax)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def devices(request):
|
def devices(request):
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
user = request.user
|
user = request.user
|
||||||
|
@ -89,6 +97,7 @@ def editdevice(request, device_id):
|
||||||
if subnet[0] in subnets:
|
if subnet[0] in subnets:
|
||||||
device[0].name = request.POST.get("name", "")
|
device[0].name = request.POST.get("name", "")
|
||||||
device[0].network = subnet[0]
|
device[0].network = subnet[0]
|
||||||
|
device[0].reboot = True if request.POST.get("reboot", "0") == "True" else False
|
||||||
device[0].save()
|
device[0].save()
|
||||||
|
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
31
static/js/devices.js
Normal file
31
static/js/devices.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
function timeSince(obj) {
|
||||||
|
last = new Date(obj)
|
||||||
|
var seconds = Math.floor((new Date() - last) / 1000);
|
||||||
|
interval = Math.floor(seconds / 3600);
|
||||||
|
out = "";
|
||||||
|
|
||||||
|
if (interval > 24) return "at " + last.toDateString().substr(4) + " " + last.toLocaleTimeString();
|
||||||
|
if (interval > 1) out = interval + " hours ";
|
||||||
|
|
||||||
|
interval = Math.floor(seconds / 60);
|
||||||
|
|
||||||
|
if (seconds < 120) out = seconds + " seconds "
|
||||||
|
else if (interval > 1) out = out + interval + " minutes ";
|
||||||
|
|
||||||
|
return out + "ago"
|
||||||
|
}
|
||||||
|
|
||||||
|
function styleStatus(msg, device) {
|
||||||
|
device_status = $("#" + device + "-indicator");
|
||||||
|
device_ip = $("#" + device + "-ip");
|
||||||
|
|
||||||
|
device_status.css("color", msg.status == 1 ? "green" : (msg.status == 0 ? "red" : "grey"))
|
||||||
|
|
||||||
|
if (msg.hasOwnProperty("ip")) {
|
||||||
|
device_ip.text(msg.ip + (msg.status == 1 ? "" :" (" + timeSince(msg.time) + ")"));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateStatus(device_id) {
|
||||||
|
$.getJSON( "/devices/" + device_id + "/ping/", function(json) { styleStatus(json, device_id); });
|
||||||
|
};
|
|
@ -7,7 +7,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
SECRET_KEY = '=go8&h#^kh6ksr11e2z-@4qqd6t%63$x#-!s#l_yhw@oyanrys'
|
SECRET_KEY = '=go8&h#^kh6ksr11e2z-@4qqd6t%63$x#-!s#l_yhw@oyanrys'
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = False
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = ["admin360.kumi.host"]
|
ALLOWED_HOSTS = ["admin360.kumi.host"]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue