added settings page

This commit is contained in:
Maxi Quoß
2021-09-28 00:22:21 +02:00
parent 1dbc0308f2
commit 45f8b1b7d2
20 changed files with 500 additions and 242 deletions

View File

@@ -1,7 +1,13 @@
# Django Wake on LAN
<div align="center" width="100%">
<img src="app/wol/static/img/favicon.png" width="128" />
</div>
A simple wake on lan app written with Django, Django-Channels (websockets), Celery and Redis.
<a target="_blank" href="https://github.com/seriousm4x/django-wake-on-lan"><img src="https://img.shields.io/github/stars/seriousm4x/django-wake-on-lan" /></a> <a target="_blank" href="https://hub.docker.com/r/seriousm4x/django-wol"><img src="https://img.shields.io/docker/pulls/seriousm4x/django-wol" /></a> <a target="_blank" href="https://hub.docker.com/r/seriousm4x/django-wol"><img src="https://img.shields.io/docker/v/seriousm4x/django-wol/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/seriousm4x/django-wake-on-lan"><img src="https://img.shields.io/github/last-commit/seriousm4x/django-wake-on-lan" /></a>
| Dark | Light |
| -------------------- | --------------------- |
| ![](https://raw.githubusercontent.com/seriousm4x/django-wake-on-lan/master/assets/dark.png) | ![](https://raw.githubusercontent.com/seriousm4x/django-wake-on-lan/master/assets/light.png) |
@@ -35,6 +41,9 @@ You can use the example [docker-compose.yml](docker-compose.yml) file and just r
| POSTGRES_USER | Str | Database user |
| POSTGRES_PASSWORD | Str | Database password |
| POSTGRES_DB | Str | Database name |
| PING_INTERVAL | Int | Time between pings |
| ENABLE_NOTIFICATIONS | Bool | Show notifications in the bottom right corner |
## Manage devices

View File

@@ -1,4 +1,5 @@
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_wol.settings")
@@ -8,11 +9,11 @@ app = Celery("dango_wol")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.conf.beat_schedule = {
"ping_devices_5s": {
"ping_devices": {
"task": "wol.tasks.status",
"schedule": 5
"schedule": int(os.getenv("PING_INTERVAL"))
},
"scheduled_wakes_1s": {
"scheduled_wakes": {
"task": "wol.tasks.scheduled_wakes",
"schedule": 1
}

View File

@@ -141,3 +141,5 @@ USE_TZ = True
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
VERSION = "v1.2.0"

View File

@@ -12,7 +12,11 @@ fi
# set visitors to 0
python -u manage.py shell -c "from wol.models import Websocket; [i.delete() for i in Websocket.objects.all()]; Websocket.objects.create(visitors=0)"
# set notifications
if [ -n "$ENABLE_NOTIFICATIONS" ]; then
python -u manage.py shell -c "from wol.models import Settings; Settings.objects.update_or_create(id=1, defaults={'enable_notifications': '$ENABLE_NOTIFICATIONS'})"
fi
celery -A django_wol worker &
celery -A django_wol beat &
gunicorn --bind 0.0.0.0:"$DJANGO_PORT" --workers 4 django_wol.asgi:application -k uvicorn.workers.UvicornWorker

View File

@@ -1,6 +1,6 @@
from django.contrib import admin
from wol.models import Device
from wol.models import Device, Settings
class DeviceAdmin(admin.ModelAdmin):
@@ -8,4 +8,14 @@ class DeviceAdmin(admin.ModelAdmin):
search_fields = ["name", "ip", "mac"]
list_filter = ["name", "ip", "mac"]
class SettingsAdmin(admin.ModelAdmin):
list_display = ["enable_notifications",
"enable_console_logging", "sort_by"]
class Meta:
verbose_name_plural = "Settings"
admin.site.register(Device, DeviceAdmin)
admin.site.register(Settings, SettingsAdmin)

12
app/wol/forms.py Normal file
View File

@@ -0,0 +1,12 @@
from django import forms
from .models import Settings
class SettingsForm(forms.Form):
class Meta:
model = Settings
fields = []
notifications = forms.CharField(widget=forms.RadioSelect, label="notifications")
console = forms.CharField(widget=forms.RadioSelect, label="console")
sort = forms.ChoiceField(choices=[("name", "name"), ("ip", "ip")], widget=forms.RadioSelect, label="sort")

View File

@@ -0,0 +1,23 @@
# Generated by Django 3.2.7 on 2021-09-27 16:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wol', '0007_device_scheduled_wake'),
]
operations = [
migrations.CreateModel(
name='Settings',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ping_interval', models.PositiveSmallIntegerField(default=5)),
('enable_notifications', models.BooleanField(default=True)),
('enable_console_logging', models.BooleanField(default=True)),
('sort_by', models.SlugField(default='name')),
],
),
]

View File

@@ -0,0 +1,17 @@
# Generated by Django 3.2.7 on 2021-09-27 19:05
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wol', '0008_settings'),
]
operations = [
migrations.RemoveField(
model_name='settings',
name='ping_interval',
),
]

View File

@@ -11,3 +11,8 @@ class Device(models.Model):
class Websocket(models.Model):
visitors = models.PositiveSmallIntegerField(blank=False, null=False, default=0)
class Settings(models.Model):
enable_notifications = models.BooleanField(default=True)
enable_console_logging = models.BooleanField(default=False)
sort_by = models.SlugField(default="name")

View File

@@ -71,13 +71,14 @@
flex-shrink: unset;
}
.section.settings {
padding: 0;
.checkbox, .radio {
display: table-header-group;
}
@media (prefers-color-scheme: dark) {
.box {
background-color: var(--box-bg);
box-shadow: none;
}
.button.is-static {
@@ -92,6 +93,10 @@
.modal-background {
background-color: rgba(0, 0, 0, 0.86);
}
.navbar-menu.is-active {
box-shadow: 0 5px 5px rgba(0, 0, 0, 0.2)
}
}
@keyframes green-pulse {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -1,6 +1,7 @@
'use strict';
document.addEventListener('DOMContentLoaded', function () {
// Modals
var rootEl = document.documentElement;
@@ -47,6 +48,30 @@ document.addEventListener('DOMContentLoaded', function () {
}
});
// Navbar
// Get all "navbar-burger" elements
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Check if there are any navbar burgers
if ($navbarBurgers.length > 0) {
// Add a click event on each of them
$navbarBurgers.forEach(el => {
el.addEventListener('click', () => {
// Get the target from the "data-target" attribute
const target = el.dataset.target;
const $target = document.getElementById(target);
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
}
// Utils
function getAll(selector) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -122,7 +122,7 @@ function setDeviceUp(device) {
var scheduleModalButton = document.getElementById(device.id + "-btn-schedule");
// check if device was down before
if (statusDot.classList.contains("dot-down")) {
if (statusDot.classList.contains("dot-down") && enableNotifications) {
notif.show("Device now up!", device.name + " is now up.", "is-success", 5000);
}
@@ -174,7 +174,7 @@ function setDeviceDown(device) {
var scheduleModalButton = document.getElementById(device.id + "-btn-schedule");
// check if device was up before
if (statusDot.classList.contains("dot-up")) {
if (statusDot.classList.contains("dot-up") && enableNotifications ) {
notif.show("Device now down!", device.name + " is now down.", "is-danger", 5000);
}
@@ -215,7 +215,6 @@ function addSchedule(id, name, datetime) {
if (!(datetime)) {
return;
}
console.log(datetime);
socket.send(JSON.stringify({
"message": "add_schedule",
"id": id,
@@ -239,7 +238,9 @@ function deleteSchedule(id, name) {
var socket = new WebSocket("ws://" + location.host + "/wol/");
socket.onmessage = function (event) {
var message = JSON.parse(event.data);
console.log(message);
if (enableConsoleLogging) {
console.log(message);
}
// set devices up or down
if ("device" in message) {
@@ -256,35 +257,47 @@ socket.onmessage = function (event) {
document.getElementById("visitors").innerHTML = message.visitors + ' visitor';
} else {
document.getElementById("visitors").innerHTML = message.visitors + ' visitors';
notif.show("Visitors updated", "There are currently " + message.visitors + " visitors", "is-info", 5000);
if (enableNotifications) {
notif.show("Visitors updated", "There are currently " + message.visitors + " visitors", "is-info", 5000);
}
}
}
// set wake by client
if ("wake" in message) {
document.getElementById(message.wake.id + "-btn-wake").classList.add("is-loading");
notif.show("Wake started", message.wake.name + " has been started.", "is-info", 5000);
if (enableNotifications) {
notif.show("Wake started", message.wake.name + " has been started.", "is-info", 5000);
}
}
// set wake by schedule
if ("wake_schedule" in message) {
document.getElementById(message.wake_schedule.id + "-btn-wake").classList.add("is-loading");
document.getElementById(message.wake_schedule.id + "-schedule-notice").innerHTML = "";
notif.show("Scheduled wake started", message.wake_schedule.name + " has been started.", "is-info", 5000);
if (enableNotifications) {
notif.show("Scheduled wake started", message.wake_schedule.name + " has been started.", "is-info", 5000);
}
}
// add schedule
if ("add_schedule" in message) {
document.getElementById(message.add_schedule.id + "-schedule-notice").innerHTML = `<p>Scheduled wake set:<br>${message.add_schedule.datetime}</p>`;
notif.show("Schedule added", "A wake up event has been scheduled for " + message.add_schedule.name, "is-info", 5000);
if (enableNotifications) {
notif.show("Schedule added", "A wake up event has been scheduled for " + message.add_schedule.name, "is-info", 5000);
}
}
// delete schedule
if ("delete_schedule" in message) {
document.getElementById(message.delete_schedule.id + "-schedule-notice").innerHTML = "";
notif.show("Schedule deleted", "A wake up event has been deleted for " + message.delete_schedule.name, "is-info", 5000);
if (enableNotifications) {
notif.show("Schedule deleted", "A wake up event has been deleted for " + message.delete_schedule.name, "is-info", 5000);
}
}
}
socket.onclose = function (event) {
notif.show("Connection closed", "Websocket connection has closed", "is-danger", 5000);
if (enableNotifications) {
notif.show("Connection closed", "Websocket connection has closed", "is-danger", 5000);
}
}

View File

@@ -6,7 +6,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Wake on LAN</title>
<title>wake on lan</title>
<link rel="icon" type="image/png" href="{% static 'img/favicon.png' %}">
<link rel="stylesheet" href="{% static 'css/bulma.min.css' %}">
<link rel="stylesheet" href="{% static 'css/bulma-prefers-dark.min.css' %}">
@@ -15,150 +15,159 @@
<link rel="stylesheet" href="{% static 'css/bulma-notifications.css' %}">
</head>
<body class="px-4">
<section class="section">
<div class="container">
<div class="columns is-vcentered">
<div class="column is-one-third">
<h1 class="title">
Wake on LAN
</h1>
<p class="subtitle">
Wake your devices with a simple click!
</p>
</div>
<div class="column is-one-third">
<div class="field is-grouped">
<p class="control">
<a class="button is-light" href="/settings">
<span>Settings</span>
<span class="icon is-small">
<i class="fas fa-cogs"></i>
</span>
</a>
</p>
<p class="control">
<a class="button is-light" href="/admin">
<span>Admin</span>
<span class="icon is-small">
<i class="fas fa-user-cog"></i>
</span>
</a>
</p>
<p class="control">
<a class="button is-static is-light">
<span id="visitors">{{ visitors }} visitors</span>
<span class="icon is-small">
<i class="fas fa-users"></i>
</span>
</a>
</p>
</div>
</div>
<body>
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img class="ml-2" src="{% static 'img/favicon.png' %}" width="28" height="28">
</a>
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item" href="/">
Devices
</a>
<a class="navbar-item" href="/settings/">
Settings
</a>
</div>
</div>
</section>
<div class="columns is-fullhd is-multiline">
{% for dev in devices %}
<div class="column is-half-fullhd is-full-widescreen is-full-desktop is-full-tablet is-full-mobile">
<div class="box mb-3 box-waiting" id="{{ dev.id }}-container">
<div class="columns is-centered">
<div class="column">
<div class="container">
<h1 class="title">
{{ dev.name }}
</h1>
<p><strong>ip</strong>: {{ dev.ip }}</p>
<p><strong>mac</strong>: {{ dev.mac }}</p>
<p><strong>netmask</strong>: {{ dev.netmask }}</p>
</div>
</div>
<div class="column">
<div class="container">
<h1 class="title">
Status
</h1>
<p id="{{ dev.id }}-status">
<i id="{{ dev.id }}-dot" class="fas fa-circle fa-2x dot-waiting"></i>
</p>
</div>
</div>
<div class="column">
<div class="container">
<h1 class="title">
Ports
</h1>
<div id="{{ dev.id }}-ports">
<ul>
<li><i class="fas fa-circle fa-fw dot-waiting"></i> VNC (5900)</li>
<li><i class="fas fa-circle fa-fw dot-waiting"></i> RDP (3389)</li>
<li><i class="fas fa-circle fa-fw dot-waiting"></i> SSH (22)</li>
</ul>
</nav>
<div class="container">
<section class="section">
<h1 class="title is-size-2">
Devices <span id="visitors" class="tag is-primary is-light">{{ visitors }} visitors</span>
</h1>
<p class="subtitle">
Wake on LAN
</p>
</section>
</div>
<div class="p-4">
<div class="columns is-fullhd is-multiline">
{% for dev in devices %}
<div class="column is-half-fullhd is-full-widescreen is-full-desktop is-full-tablet is-full-mobile">
<div class="box mb-3 box-waiting" id="{{ dev.id }}-container">
<div class="columns is-centered">
<div class="column">
<div class="container">
<h1 class="title">
{{ dev.name }}
</h1>
<p><strong>ip</strong>: {{ dev.ip }}</p>
<p><strong>mac</strong>: {{ dev.mac }}</p>
<p><strong>netmask</strong>: {{ dev.netmask }}</p>
</div>
</div>
</div>
<div class="column">
<div class="container">
<h1 class="title">
Actions
</h1>
<div class="buttons">
<button class="button is-success" id="{{ dev.id }}-btn-wake" name="wake"
aria-label="wake" onclick="wakeDevice({{ dev.id }})" disabled>
<span>Wake</span>
<span class="icon is-small">
<i class="fas fa-play"></i>
</span>
</button>
<button id="{{ dev.id }}-btn-schedule" class="button is-light modal-button" data-target="{{ dev.id }}-modal" aria-haspopup="true" disabled>
<span class="icon">
<i class="fas fa-clock"></i>
</span>
</button>
</div>
<div id="{{ dev.id }}-schedule-notice">
{% if dev.scheduled_wake %}
<p>
Scheduled wake set:<br>{{ dev.scheduled_wake|date:"c" }}
<div class="column">
<div class="container">
<h1 class="title">
Status
</h1>
<p id="{{ dev.id }}-status">
<i id="{{ dev.id }}-dot" class="fas fa-circle fa-2x dot-waiting"></i>
</p>
{% endif %}
</div>
<p></p>
</div>
<div class="column">
<div class="container">
<h1 class="title">
Ports
</h1>
<div id="{{ dev.id }}-ports">
<ul>
<li><i class="fas fa-circle fa-fw dot-waiting"></i> VNC (5900)</li>
<li><i class="fas fa-circle fa-fw dot-waiting"></i> RDP (3389)</li>
<li><i class="fas fa-circle fa-fw dot-waiting"></i> SSH (22)</li>
</ul>
</div>
</div>
</div>
<div class="column">
<div class="container">
<h1 class="title">
Actions
</h1>
<div class="buttons">
<button class="button is-success" id="{{ dev.id }}-btn-wake" name="wake"
aria-label="wake" onclick="wakeDevice({{ dev.id }})" disabled>
<span>Wake</span>
<span class="icon is-small">
<i class="fas fa-play"></i>
</span>
</button>
<button id="{{ dev.id }}-btn-schedule" class="button is-light modal-button" data-target="{{ dev.id }}-modal" aria-haspopup="true" disabled>
<span class="icon">
<i class="fas fa-clock"></i>
</span>
</button>
</div>
<div id="{{ dev.id }}-schedule-notice">
{% if dev.scheduled_wake %}
<p>
Scheduled wake:<br>{{ dev.scheduled_wake|date:"c" }}
</p>
{% endif %}
</div>
<p></p>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="{{ dev.id }}-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-content">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Schedule wake up for {{ dev.name }}</p>
<button class="delete" aria-label="close"></button>
</header>
<section class="modal-card-body">
<label for="{{ dev.id }}-input">Choose date and time:</label>
<input type="datetime-local" id="{{ dev.id }}-input" class="input">
</section>
<footer class="modal-card-foot">
<button class="button is-success" id="{{ dev.id }}-btn-schedule-save"
onclick="addSchedule({{ dev.id }}, '{{ dev.name }}', document.getElementById('{{ dev.id }}-input').value)">Save changes</button>
<button class="button is-light-dark">Cancel</button>
<button class="button is-danger is-pulled-right" onclick="deleteSchedule({{ dev.id }}, '{{ dev.name }}')">Delete</button>
</footer>
<div id="{{ dev.id }}-modal" class="modal">
<div class="modal-background"></div>
<div class="modal-content">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Schedule wake up for {{ dev.name }}</p>
<button class="delete" aria-label="close"></button>
</header>
<section class="modal-card-body">
<label for="{{ dev.id }}-input">Choose date and time:</label>
<input type="datetime-local" id="{{ dev.id }}-input" class="input">
</section>
<footer class="modal-card-foot">
<button class="button is-success" id="{{ dev.id }}-btn-schedule-save"
onclick="addSchedule({{ dev.id }}, '{{ dev.name }}', document.getElementById('{{ dev.id }}-input').value)">Save changes</button>
<button class="button is-light-dark">Cancel</button>
<button class="button is-danger is-pulled-right" onclick="deleteSchedule({{ dev.id }}, '{{ dev.name }}')">Delete</button>
</footer>
</div>
</div>
<button class="modal-close is-large" aria-label="close"></button>
</div>
<button class="modal-close is-large" aria-label="close"></button>
{% endfor %}
</div>
{% endfor %}
</div>
</body>
<footer>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
{% if settings.enable_notifications %}
<script>
const enableNotifications = true
</script>
{% else %}
<script>
const enableNotifications = false
</script>
{% endif %}
{% if settings.enable_console_logging %}
<script>
const enableConsoleLogging = true
</script>
{% else %}
<script>
const enableConsoleLogging = false
</script>
{% endif %}
<script src="{% static 'js/bulma.js' %}"></script>
<script src="{% static 'js/main.js' %}"></script>
<script src="{% static 'js/modal.js' %}"></script>
</footer>
</html>

View File

@@ -16,115 +16,203 @@
<link rel="stylesheet" href="{% static 'css/slider.css' %}">
</head>
<body class="px-4">
<section class="section">
<div class="container">
<div class="columns is-vcentered">
<div class="column is-one-third">
<h1 class="title">
Wake on LAN
</h1>
<p class="subtitle">
Settings
</p>
<body>
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img class="ml-2" src="{% static 'img/favicon.png' %}" width="28" height="28">
</a>
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item" href="/">
Devices
</a>
<a class="navbar-item" href="/settings/">
Settings
</a>
</div>
</div>
</nav>
<div class="container">
<section class="section">
<h1 class="title is-size-2">
Settings
</h1>
<p class="subtitle">
Wake on LAN
</p>
</section>
<section class="section pt-4 pb-3">
<article class="message is-info">
<div class="message-header">
<p>Adding devices</p>
</div>
<div class="column is-one-third">
<div class="field is-grouped">
<p class="control">
<a class="button is-light" href="/">
<span>Devices</span>
<span class="icon is-small">
<i class="fas fa-desktop"></i>
</span>
</a>
</p>
<p class="control">
<a class="button is-light" href="/admin">
<span>Admin</span>
<span class="icon is-small">
<i class="fas fa-user-cog"></i>
</span>
</a>
</p>
<p class="control">
<a class="button is-static is-light">
<span id="visitors">{{ visitors }} visitors</span>
<span class="icon is-small">
<i class="fas fa-users"></i>
</span>
</a>
</p>
<div class="message-body">
Adding devices is (for now) only possible via the <a href="/admin">/admin</a> backend. A frontend solution will be implemented in the future.
</div>
</article>
</section>
<section class="section py-3">
<form action="/save_settings/" method="post">
{% csrf_token %}
<div class="box">
<h2 class="title is-size-3 mb-4">General</h2>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Notifications:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<div class="control">
<label class="radio">
<input id="noti-on" type="radio" name="notifications" value="on" {% if settings.enable_notifications %}checked{% endif %}>
Enabled
</label>
<label class="radio">
<input id="noti-off" type="radio" name="notifications" value="off" {% if not settings.enable_notifications %}checked{% endif %}>
Disabled
</label>
</div>
</div>
</div>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Console logging:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<div class="control">
<label class="radio">
<input id="console-on" type="radio" name="console" value="on" {% if settings.enable_console_logging %}checked{% endif %}>
Enabled
</label>
<label class="radio">
<input id="console-off" type="radio" name="console" value="off" {% if not settings.enable_console_logging %}checked{% endif %}>
Disabled
</label>
</div>
</div>
</div>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Sort devices by:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<div class="control">
<label class="radio">
<input id="sort-name" type="radio" name="sort" value="name" {% if settings.sort_by == "name" %}checked{% endif %}>
Name
</label>
<label class="radio">
<input id="sort-ip" type="radio" name="sort" value="ip" {% if settings.sort_by == "ip" %}checked{% endif %}>
IP
</label>
</div>
</div>
</div>
<button class="button is-primary" type="submit" value="Submit">Save</button>
</div>
</form>
</section>
<section class="section py-3">
<div class="box">
<h2 class="title is-size-3 mb-4">App info</h2>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>App version:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ app_version }}</p>
</div>
</div>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Ping interval:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ ping_interval }} seconds</p>
</div>
</div>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Devices in database:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ devices_count }}</p>
</div>
</div>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Current visitors:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ visitors }}</p>
</div>
</div>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Debug mode:</strong></span>
</div>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ debug }}</p>
</div>
</div>
</div>
</div>
</section>
<div class="container">
<div class="box">
<section class="section settings">
<h2 class="is-size-3 mb-4">General</h2>
<div class="columns">
<div class="column is-one-fifth">
<label for="ping-interval">Ping interval:</label>
</section>
<section class="section py-3">
<div class="box">
<h2 class="title is-size-3 mb-4">System info</h2>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>System:</strong></span>
</div>
<div class="column">
<input id="ping-interval" class="input is-inline is-primary w-25" type="text" placeholder="5">
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ platform.system }}</p>
</div>
</div>
<div class="columns">
<div class="column is-one-fifth">
<span class="mr-2">Enable notifications:</span>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Node:</strong></span>
</div>
<div class="column">
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ platform.node }}</p>
</div>
</div>
<div class="columns">
<div class="column is-one-fifth">
<span class="mr-2">Debug mode:</span>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Release:</strong></span>
</div>
<div class="column">
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ platform.release }}</p>
</div>
</div>
</section>
</div>
<div class="box">
<section class="section settings">
<h2 class="is-size-3 mb-4">Database</h2>
<div class="columns">
<div class="column is-one-fifth">
<label for="ping-interval">Ping interval:</label>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Version:</strong></span>
</div>
<div class="column">
<input id="ping-interval" class="input is-inline is-primary w-25" type="text" placeholder="5">
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ platform.version }}</p>
</div>
</div>
<div class="columns">
<div class="column is-one-fifth">
<span class="mr-2">Enable notifications:</span>
<div class="columns is-mobile">
<div class="column is-half-mobile is-one-thirds-tablet is-one-quarter-desktop is-one-fifth-widescreen">
<span class="mr-2"><strong>Machine:</strong></span>
</div>
<div class="column">
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
<div class="column is-half-mobile is-two-thirds-tablet is-three-quarters-desktop is-four-fifths-widescreen">
<p>{{ platform.machine }}</p>
</div>
</div>
</section>
</div>
</div>
</section>
</div>
</body>
<footer>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'js/modal.js' %}"></script>
<script src="{% static 'js/bulma.js' %}"></script>
</footer>
</html>

View File

@@ -4,5 +4,6 @@ from wol import views
urlpatterns = [
path("", views.index, name="index"),
path("settings/", views.settings, name="settings")
path("settings/", views.settings, name="settings"),
path("save_settings/", views.save_settings, name="save_settings")
]

View File

@@ -1,23 +1,57 @@
from django.shortcuts import render
import os
import platform
from wol.models import Device, Websocket
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django_wol.settings import VERSION as app_version
from .forms import SettingsForm
from .models import Device, Settings, Websocket
def index(request):
devices = Device.objects.all().order_by("name")
conf = Settings.objects.first()
devices = Device.objects.all().order_by(conf.sort_by)
visitors = Websocket.objects.first().visitors
context = {
"devices": devices,
"visitors": visitors
"visitors": visitors,
"settings": conf
}
return render(request, "wol/index.html", context)
def settings(request):
conf = Settings.objects.first()
devices_count = Device.objects.all().count()
visitors = Websocket.objects.first().visitors
context = {
"test": "ja lol ey"
"settings": conf,
"ping_interval": os.getenv("PING_INTERVAL"),
"devices_count": devices_count,
"platform": platform.uname(),
"app_version": app_version,
"debug": os.getenv("DJANGO_DEBUG"),
"visitors": visitors
}
return render(request, "wol/settings.html", context)
return render(request, "wol/settings.html", context)
def save_settings(request):
if request.method == "POST":
form = SettingsForm(request.POST)
if form.is_valid():
Settings.objects.update_or_create(
id = 1,
defaults = {
"enable_notifications": True if form.cleaned_data["notifications"] == "on" else False,
"enable_console_logging": True if form.cleaned_data["console"] == "on" else False,
"sort_by": form.cleaned_data["sort"]
}
)
return HttpResponseRedirect('/settings/')

View File

@@ -2,7 +2,8 @@ version: "3"
services:
wol_django:
container_name: wol_django
image: seriousm4x/django-wol:latest
#image: seriousm4x/django-wol:latest
build: .
network_mode: host
depends_on:
- wol_redis
@@ -16,6 +17,8 @@ services:
- DJANGO_LANGUAGE_CODE=de
- DJANGO_TIME_ZONE=Europe/Berlin
- DJANGO_PORT=8000
- PING_INTERVAL=5
- ENABLE_NOTIFICATIONS=True
wol_redis:
container_name: wol_redis
image: redis:6