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
|
||||
__pycache__
|
||||
*.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)
|
||||
lasttime = models.DateTimeField("Last Received Heartbeat", blank=True, null=True)
|
||||
secret = models.CharField("Secret", default=getRandom, max_length=128)
|
||||
reboot = models.BooleanField("Trigger Reboot", default=False)
|
||||
|
||||
def __str__(self):
|
||||
return "%s%s" % (self.serial, " (%s)" % self.curip if self.curip else "")
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
<title>VPN360 Device Administration</title>
|
||||
|
||||
{% load static %}
|
||||
|
||||
<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 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://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.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>
|
||||
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
<option {% if choice.intip == device.network.intip %} selected {% endif %} value="{{ choice.intip }}">{{ choice.intip}} ({{ choice.extip }})</option>
|
||||
{% endfor %}
|
||||
</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>
|
||||
<button type="submit" class="btn btn-success">Apply Changes</button>
|
||||
<a class="btn btn-danger" href="/" role="button">Cancel</a>
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
|
||||
{% for device in devices %}
|
||||
<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>{{ 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><a href="/devices/{{ device.id }}/edit"><i class="fas fa-edit"></i></a></td>
|
||||
</tr>
|
||||
|
@ -32,10 +32,17 @@
|
|||
</table>
|
||||
</div>
|
||||
|
||||
<script src="/js/devices.js"></script>
|
||||
|
||||
<script>
|
||||
/* $(document).ready(function() {
|
||||
/*$(document).ready(function() {
|
||||
$('#table').DataTable();
|
||||
}); */
|
||||
});*/
|
||||
|
||||
{% for device in devices %}
|
||||
updateStatus({{ device.id }});
|
||||
setInterval(updateStatus, 3000, {{ device.id }});
|
||||
{% endfor %}
|
||||
</script>
|
||||
|
||||
|
||||
|
|
|
@ -21,34 +21,42 @@ def heartbeat(request):
|
|||
device.curip = request.POST.get("ip", "")
|
||||
device.lasttime = timezone.now()
|
||||
device.save()
|
||||
return HttpResponse("")
|
||||
return HttpResponse("reboot" if device.reboot else "")
|
||||
|
||||
@csrf_exempt
|
||||
def hosts(request):
|
||||
device = get_object_or_404(Device, secret=request.POST.get("secret", ""))
|
||||
device.reboot = False
|
||||
device.save()
|
||||
return render(request, "manager/hosts", {"device": device})
|
||||
|
||||
def ping(request, device_id):
|
||||
if request.user.is_authenticated:
|
||||
device = None
|
||||
ajax = '{\n "status": '
|
||||
|
||||
for organization in Organization.objects.filter(users=request.user):
|
||||
device = device or Device.objects.filter(id=device_id, organization=organization)
|
||||
|
||||
if not device:
|
||||
return HttpResponse("-1")
|
||||
ajax += "-1"
|
||||
|
||||
try:
|
||||
socket.inet_aton(device[0].curip)
|
||||
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.
|
||||
else:
|
||||
try:
|
||||
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:
|
||||
return HttpResponse("-3")
|
||||
except:
|
||||
ajax += "-3"
|
||||
|
||||
else:
|
||||
return HttpResponse("-2")
|
||||
ajax += "-2"
|
||||
|
||||
ajax += "\n}"
|
||||
return HttpResponse(ajax)
|
||||
|
||||
|
||||
|
||||
def devices(request):
|
||||
if request.user.is_authenticated:
|
||||
user = request.user
|
||||
|
@ -89,6 +97,7 @@ def editdevice(request, device_id):
|
|||
if subnet[0] in subnets:
|
||||
device[0].name = request.POST.get("name", "")
|
||||
device[0].network = subnet[0]
|
||||
device[0].reboot = True if request.POST.get("reboot", "0") == "True" else False
|
||||
device[0].save()
|
||||
|
||||
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'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ["admin360.kumi.host"]
|
||||
|
||||
|
|
Loading…
Reference in a new issue