mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2026-01-01 14:16:18 +00:00
Add forms for Worker and ClusterSettings with translations and workers list template
This commit is contained in:
139
cluster/forms.py
Normal file
139
cluster/forms.py
Normal file
@@ -0,0 +1,139 @@
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Column, HTML, Layout, Row, Submit
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .models import ClusterSettings, Worker
|
||||
|
||||
|
||||
class WorkerForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Worker
|
||||
fields = ['name', 'enabled', 'ip_lock', 'ip_address', 'country', 'city', 'hostname']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['name'].label = _("Name")
|
||||
self.fields['enabled'].label = _("Enabled")
|
||||
self.fields['ip_lock'].label = _("IP Lock")
|
||||
self.fields['ip_address'].label = _("IP Address")
|
||||
self.fields['country'].label = _("Country")
|
||||
self.fields['city'].label = _("City")
|
||||
self.fields['hostname'].label = _("Hostname")
|
||||
|
||||
back_label = _("Back")
|
||||
delete_label = _("Delete")
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
|
||||
if self.instance.pk:
|
||||
delete_html = f"<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>{delete_label}</a>"
|
||||
else:
|
||||
delete_html = ''
|
||||
|
||||
self.helper.layout = Layout(
|
||||
Row(
|
||||
Column('name', css_class='form-group col-md-6 mb-0'),
|
||||
Column('enabled', css_class='form-group col-md-6 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column('ip_lock', css_class='form-group col-md-6 mb-0'),
|
||||
Column('ip_address', css_class='form-group col-md-6 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column('country', css_class='form-group col-md-4 mb-0'),
|
||||
Column('city', css_class='form-group col-md-4 mb-0'),
|
||||
Column('hostname', css_class='form-group col-md-4 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column(
|
||||
Submit('submit', _('Save'), css_class='btn btn-success'),
|
||||
HTML(f' <a class="btn btn-secondary" href="/cluster/">{back_label}</a> '),
|
||||
HTML(delete_html),
|
||||
css_class='col-md-12'),
|
||||
css_class='form-row'
|
||||
)
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
name = cleaned_data.get('name')
|
||||
ip_lock = cleaned_data.get('ip_lock')
|
||||
ip_address = cleaned_data.get('ip_address')
|
||||
|
||||
if Worker.objects.filter(name=name).exclude(pk=self.instance.pk if self.instance else None).exists():
|
||||
raise ValidationError(_("A worker with that name already exists."))
|
||||
|
||||
if ip_lock and not ip_address:
|
||||
raise ValidationError(_("IP Address is required when IP Lock is enabled."))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class ClusterSettingsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ClusterSettings
|
||||
fields = [
|
||||
'enabled', 'primary_enable_wireguard', 'stats_sync_interval',
|
||||
'stats_cache_interval', 'cluster_mode', 'restart_mode', 'worker_display'
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['enabled'].label = _("Cluster Enabled")
|
||||
self.fields['primary_enable_wireguard'].label = _("Primary Enable WireGuard")
|
||||
self.fields['stats_sync_interval'].label = _("Stats Sync Interval (seconds)")
|
||||
self.fields['stats_cache_interval'].label = _("Stats Cache Interval (seconds)")
|
||||
self.fields['cluster_mode'].label = _("Cluster Mode")
|
||||
self.fields['restart_mode'].label = _("Restart Mode")
|
||||
self.fields['worker_display'].label = _("Worker Display")
|
||||
|
||||
back_label = _("Back")
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
|
||||
self.helper.layout = Layout(
|
||||
Row(
|
||||
Column('enabled', css_class='form-group col-md-6 mb-0'),
|
||||
Column('primary_enable_wireguard', css_class='form-group col-md-6 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column('stats_sync_interval', css_class='form-group col-md-6 mb-0'),
|
||||
Column('stats_cache_interval', css_class='form-group col-md-6 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column('cluster_mode', css_class='form-group col-md-6 mb-0'),
|
||||
Column('restart_mode', css_class='form-group col-md-6 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column('worker_display', css_class='form-group col-md-12 mb-0'),
|
||||
css_class='form-row'
|
||||
),
|
||||
Row(
|
||||
Column(
|
||||
Submit('submit', _('Save'), css_class='btn btn-success'),
|
||||
HTML(f' <a class="btn btn-secondary" href="/cluster/">{back_label}</a> '),
|
||||
css_class='col-md-12'),
|
||||
css_class='form-row'
|
||||
)
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
stats_sync_interval = cleaned_data.get('stats_sync_interval')
|
||||
stats_cache_interval = cleaned_data.get('stats_cache_interval')
|
||||
|
||||
if stats_sync_interval and stats_sync_interval < 10:
|
||||
raise ValidationError(_("Stats sync interval must be at least 10 seconds."))
|
||||
|
||||
if stats_cache_interval and stats_cache_interval < 10:
|
||||
raise ValidationError(_("Stats cache interval must be at least 10 seconds."))
|
||||
|
||||
return cleaned_data
|
||||
135
cluster/views.py
135
cluster/views.py
@@ -1 +1,134 @@
|
||||
# Create your views here.
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from user_manager.models import UserAcl
|
||||
from .forms import WorkerForm, ClusterSettingsForm
|
||||
from .models import ClusterSettings, Worker
|
||||
|
||||
|
||||
@login_required
|
||||
def cluster_main(request):
|
||||
"""Main cluster page with workers list"""
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||
|
||||
page_title = _('Cluster')
|
||||
workers = Worker.objects.all().order_by('name')
|
||||
context = {'page_title': page_title, 'workers': workers}
|
||||
return render(request, 'cluster/workers_list.html', context)
|
||||
|
||||
|
||||
@login_required
|
||||
def worker_manage(request):
|
||||
"""Add/Edit worker view"""
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||
|
||||
worker = None
|
||||
if 'uuid' in request.GET:
|
||||
worker = get_object_or_404(Worker, uuid=request.GET['uuid'])
|
||||
form = WorkerForm(instance=worker)
|
||||
page_title = _('Edit Worker: ') + worker.name
|
||||
|
||||
if request.GET.get('action') == 'delete':
|
||||
worker_name = worker.name
|
||||
if request.GET.get('confirmation') == 'delete':
|
||||
worker.delete()
|
||||
messages.success(request, _('Worker deleted|Worker deleted: ') + worker_name)
|
||||
return redirect('/cluster/')
|
||||
else:
|
||||
messages.warning(request, _('Worker not deleted|Invalid confirmation.'))
|
||||
return redirect('/cluster/')
|
||||
else:
|
||||
form = WorkerForm()
|
||||
page_title = _('Add Worker')
|
||||
|
||||
if request.method == 'POST':
|
||||
if worker:
|
||||
form = WorkerForm(request.POST, instance=worker)
|
||||
else:
|
||||
form = WorkerForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
worker = form.save()
|
||||
if worker.pk:
|
||||
messages.success(request, _('Worker updated|Worker updated: ') + worker.name)
|
||||
else:
|
||||
messages.success(request, _('Worker created|Worker created: ') + worker.name)
|
||||
return redirect('/cluster/')
|
||||
|
||||
form_description = {
|
||||
'size': 'col-lg-6',
|
||||
'content': _('''
|
||||
<h5>Worker Configuration</h5>
|
||||
<p>Configure a cluster worker node that will synchronize with this primary instance.</p>
|
||||
|
||||
<h5>Name</h5>
|
||||
<p>A unique name to identify this worker.</p>
|
||||
|
||||
<h5>IP Address</h5>
|
||||
<p>The IP address of the worker node. Leave empty if IP lock is disabled.</p>
|
||||
|
||||
<h5>IP Lock</h5>
|
||||
<p>When enabled, the worker can only connect from the specified IP address.</p>
|
||||
|
||||
<h5>Location Information</h5>
|
||||
<p>Optional location details for this worker (country, city, hostname).</p>
|
||||
''')
|
||||
}
|
||||
|
||||
context = {
|
||||
'page_title': page_title,
|
||||
'form': form,
|
||||
'worker': worker,
|
||||
'instance': worker,
|
||||
'form_description': form_description
|
||||
}
|
||||
return render(request, 'generic_form.html', context)
|
||||
|
||||
|
||||
@login_required
|
||||
def cluster_settings(request):
|
||||
"""Cluster settings configuration"""
|
||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||
|
||||
cluster_settings, created = ClusterSettings.objects.get_or_create(name='cluster_settings')
|
||||
page_title = _('Cluster Settings')
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ClusterSettingsForm(request.POST, instance=cluster_settings)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _('Cluster settings updated successfully.'))
|
||||
return redirect('/cluster/')
|
||||
else:
|
||||
form = ClusterSettingsForm(instance=cluster_settings)
|
||||
|
||||
form_description = {
|
||||
'size': 'col-lg-6',
|
||||
'content': _('''
|
||||
<h5>Cluster Mode</h5>
|
||||
<p>Configure how the cluster operates and synchronizes configurations between nodes.</p>
|
||||
|
||||
<h5>Sync Intervals</h5>
|
||||
<p>Configure how frequently statistics and cache data are synchronized between cluster nodes.</p>
|
||||
|
||||
<h5>Restart Mode</h5>
|
||||
<p>Choose whether WireGuard services should be automatically restarted when configurations change, or if manual intervention is required.</p>
|
||||
|
||||
<h5>Worker Display</h5>
|
||||
<p>Select how workers should be identified in the interface - by name, server address, location, or a combination.</p>
|
||||
''')
|
||||
}
|
||||
|
||||
context = {
|
||||
'page_title': page_title,
|
||||
'form': form,
|
||||
'cluster_settings': cluster_settings,
|
||||
'instance': cluster_settings,
|
||||
'form_description': form_description
|
||||
}
|
||||
return render(request, 'generic_form.html', context)
|
||||
|
||||
Reference in New Issue
Block a user