mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2026-01-31 11:36:18 +00:00
Update peer management view and forms.
This commit is contained in:
@@ -7,43 +7,65 @@
|
|||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3 class="card-title">{% trans 'Peer Configuration' %}</h3>
|
<h3 class="card-title">{% trans 'Peer Configuration' %}</h3>
|
||||||
</div>
|
</div>
|
||||||
<form method="post">
|
<div class="card-body">
|
||||||
{% csrf_token %}
|
<div class="row">
|
||||||
<div class="card-body row">
|
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<!-- Name -->
|
<!-- Name -->
|
||||||
<div class="form-group">
|
<div class="form-group border-bottom pb-3">
|
||||||
<label for="{{ form.name.id_for_label }}">{{ form.name.label }}</label>
|
<label>{% trans 'Name' %}</label>
|
||||||
<input type="text" class="form-control" id="{{ form.name.id_for_label }}" name="{{ form.name.html_name }}" placeholder="{% trans 'Enter Name' %}" value="{{ form.name.value|default_if_none:'' }}">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<span>{{ current_peer.name|default:"-" }}</span>
|
||||||
|
<a href="{% url 'wireguard_peer_edit_field' %}?peer={{ current_peer.uuid }}&group=name"
|
||||||
|
class="btn btn-tool">
|
||||||
|
<i class="fas fa-pen"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Persistent Keepalive -->
|
<!-- Persistent Keepalive -->
|
||||||
<div class="form-group">
|
<div class="form-group border-bottom pb-3">
|
||||||
<label for="{{ form.persistent_keepalive.id_for_label }}">{{ form.persistent_keepalive.label }}</label>
|
<label>{% trans 'Persistent Keepalive' %}</label>
|
||||||
<input type="number" class="form-control" id="{{ form.persistent_keepalive.id_for_label }}" name="{{ form.persistent_keepalive.html_name }}" placeholder="{% trans 'Persistent Keepalive' %}" value="{{ form.persistent_keepalive.value|default_if_none:'' }}" required>
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
</div>
|
<span>{{ current_peer.persistent_keepalive }}</span>
|
||||||
|
<a href="{% url 'wireguard_peer_edit_field' %}?peer={{ current_peer.uuid }}&group=keepalive"
|
||||||
<!-- Public Key -->
|
class="btn btn-tool">
|
||||||
<div class="form-group">
|
<i class="fas fa-pen"></i>
|
||||||
<label for="{{ form.public_key.id_for_label }}">{{ form.public_key.label }}</label>
|
</a>
|
||||||
<input type="text" class="form-control" id="{{ form.public_key.id_for_label }}" name="{{ form.public_key.html_name }}" placeholder="{% trans 'Public Key' %}" value="{{ form.public_key.value|default_if_none:'' }}" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Private Key -->
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="{{ form.private_key.id_for_label }}">{{ form.private_key.label }}</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="password" class="form-control" id="{{ form.private_key.id_for_label }}" name="{{ form.private_key.html_name }}" placeholder="{% trans 'Private Key' %}" value="{{ form.private_key.value|default_if_none:'' }}">
|
|
||||||
<div class="input-group-append">
|
|
||||||
<button class="btn btn-outline-secondary toggle-password" type="button"><i class="fas fa-eye"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pre-Shared Key -->
|
<!-- Keys Section -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="{{ form.pre_shared_key.id_for_label }}">{{ form.pre_shared_key.label }}</label>
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<input type="text" class="form-control" id="{{ form.pre_shared_key.id_for_label }}" name="{{ form.pre_shared_key.html_name }}" placeholder="{% trans 'Pre-Shared Key' %}" value="{{ form.pre_shared_key.value|default_if_none:'' }}" required>
|
<label class="mb-0">{% trans 'Keys' %}</label>
|
||||||
|
<a href="{% url 'wireguard_peer_edit_field' %}?peer={{ current_peer.uuid }}&group=keys"
|
||||||
|
class="btn btn-tool">
|
||||||
|
<i class="fas fa-pen"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt class="small text-muted font-weight-normal">{% trans 'Public Key' %}</dt>
|
||||||
|
<dd class="text-break">{{ current_peer.public_key }}</dd>
|
||||||
|
|
||||||
|
<dt class="small text-muted font-weight-normal">{% trans 'Private Key' %}</dt>
|
||||||
|
<dd>
|
||||||
|
{% if current_peer.private_key %}
|
||||||
|
<code>********************************************</code>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">{% trans 'Not set' %}</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt class="small text-muted font-weight-normal">{% trans 'Pre-Shared Key' %}</dt>
|
||||||
|
<dd>
|
||||||
|
{% if current_peer.pre_shared_key %}
|
||||||
|
<code>********************************************</code>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">{% trans 'Not set' %}</span>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -195,47 +217,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<button type="submit" class="btn btn-primary">{% trans 'Save' %}</button>
|
|
||||||
<a href="/peer/manage_ip_address/?peer={{ current_peer.uuid }}" class="btn btn-outline-primary">{% trans 'Add IP Address' %}</a>
|
|
||||||
<a class="btn btn-outline-secondary" href="/peer/list/?uuid={{ current_peer.wireguard_instance.uuid }}#peer-{{ current_peer.public_key }}">{% trans 'Back' %}</a>
|
<a class="btn btn-outline-secondary" href="/peer/list/?uuid={{ current_peer.wireguard_instance.uuid }}#peer-{{ current_peer.public_key }}">{% trans 'Back' %}</a>
|
||||||
<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>{% trans 'Delete Peer' %}</a>
|
<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete' onclick='openCommandDialog(this)'>{% trans 'Delete Peer' %}</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block custom_page_scripts %}
|
{% block custom_page_scripts %}
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
var alertShown = false;
|
|
||||||
var fieldsToWatch = ['id_public_key', 'id_pre_shared_key', 'id_private_key'];
|
|
||||||
function showAlert() {
|
|
||||||
if (!alertShown) {
|
|
||||||
$(document).Toasts('create', {
|
|
||||||
class: 'bg-warning',
|
|
||||||
title: '{% trans 'Action Required!' %}',
|
|
||||||
body: '{% trans 'When manually updating the "Public Key", "Pre-Shared Key", or "Private Key", please ensure the configuration is correct.' %}',
|
|
||||||
});
|
|
||||||
alertShown = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fieldsToWatch.forEach(function(fieldId) {
|
|
||||||
var field = document.getElementById(fieldId);
|
|
||||||
if (field) {
|
|
||||||
field.addEventListener('change', showAlert);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function openCommandDialog(element) {
|
function openCommandDialog(element) {
|
||||||
var command = element.getAttribute('data-command');
|
var command = element.getAttribute('data-command');
|
||||||
@@ -247,22 +240,6 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
document.querySelector('.toggle-password').addEventListener('click', function () {
|
|
||||||
let passwordInput = document.getElementById('{{ form.private_key.id_for_label }}');
|
|
||||||
let passStatus = passwordInput.getAttribute('type') === 'password';
|
|
||||||
passwordInput.setAttribute('type', passStatus ? 'text' : 'password');
|
|
||||||
this.innerHTML = passStatus ? '<i class="fas fa-eye-slash"></i>' : '<i class="fas fa-eye"></i>';
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('{{ form.private_key.id_for_label }}').addEventListener('keypress', function () {
|
|
||||||
this.setAttribute('type', 'text');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function(){
|
document.addEventListener('DOMContentLoaded', function(){
|
||||||
var buttons = document.querySelectorAll('.btn-group a');
|
var buttons = document.querySelectorAll('.btn-group a');
|
||||||
@@ -280,23 +257,4 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
var form = document.querySelector('form[method="post"]');
|
|
||||||
if (form) {
|
|
||||||
form.addEventListener('submit', function(e) {
|
|
||||||
var privateKeyField = document.getElementById('{{ form.private_key.id_for_label }}');
|
|
||||||
if (privateKeyField && privateKeyField.value.trim() === '') {
|
|
||||||
var confirmed = confirm('{% trans "The private key is empty. The peer’s configuration file and QR code will be generated without the private key.\n It must be inserted manually when importing.\n\n Do you want to continue?" %}');
|
|
||||||
if (!confirmed) {
|
|
||||||
e.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,21 +1,56 @@
|
|||||||
import ipaddress
|
import ipaddress
|
||||||
|
|
||||||
|
from crispy_forms.bootstrap import FormActions
|
||||||
|
from crispy_forms.helper import FormHelper
|
||||||
|
from crispy_forms.layout import Layout, Submit, Button
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from wireguard.models import NETMASK_CHOICES, Peer, PeerAllowedIP
|
from wireguard.models import NETMASK_CHOICES, Peer, PeerAllowedIP
|
||||||
|
|
||||||
|
|
||||||
class PeerForm(forms.ModelForm):
|
class PeerModelForm(forms.ModelForm):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.helper = FormHelper()
|
||||||
|
self.helper.form_method = 'post'
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
*self.Meta.fields,
|
||||||
|
FormActions(
|
||||||
|
Submit('save', _('Save'), css_class='btn-primary'),
|
||||||
|
Button('cancel', _('Back'), css_class='btn-outline-secondary', onclick='window.history.back()')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
class PeerNameForm(PeerModelForm):
|
||||||
name = forms.CharField(label=_('Name'), required=False)
|
name = forms.CharField(label=_('Name'), required=False)
|
||||||
public_key = forms.CharField(label=_('Public Key'), required=True)
|
|
||||||
private_key = forms.CharField(label=_('Private Key'), required=False)
|
|
||||||
pre_shared_key = forms.CharField(label=_('Pre-Shared Key'), required=True)
|
|
||||||
persistent_keepalive = forms.IntegerField(label=_('Persistent Keepalive'), required=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Peer
|
model = Peer
|
||||||
fields = ['name', 'public_key', 'private_key', 'pre_shared_key', 'persistent_keepalive']
|
fields = ['name']
|
||||||
|
|
||||||
|
|
||||||
|
class PeerKeepaliveForm(PeerModelForm):
|
||||||
|
persistent_keepalive = forms.IntegerField(
|
||||||
|
label=_('Persistent Keepalive'),
|
||||||
|
required=True,
|
||||||
|
validators=[MinValueValidator(1), MaxValueValidator(3600)],
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Peer
|
||||||
|
fields = ['persistent_keepalive']
|
||||||
|
|
||||||
|
|
||||||
|
class PeerKeysForm(PeerModelForm):
|
||||||
|
public_key = forms.CharField(label=_('Public Key'), required=True)
|
||||||
|
private_key = forms.CharField(label=_('Private Key'), required=False)
|
||||||
|
pre_shared_key = forms.CharField(label=_('Pre-Shared Key'), required=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Peer
|
||||||
|
fields = ['public_key', 'private_key', 'pre_shared_key']
|
||||||
|
|
||||||
|
|
||||||
class PeerAllowedIPForm(forms.ModelForm):
|
class PeerAllowedIPForm(forms.ModelForm):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from user_manager.models import UserAcl
|
|||||||
from wgwadmlibrary.tools import check_sort_order_conflict, deduplicate_sort_order, default_sort_peers, \
|
from wgwadmlibrary.tools import check_sort_order_conflict, deduplicate_sort_order, default_sort_peers, \
|
||||||
user_allowed_instances, user_allowed_peers, user_has_access_to_instance, user_has_access_to_peer
|
user_allowed_instances, user_allowed_peers, user_has_access_to_instance, user_has_access_to_peer
|
||||||
from wireguard.models import Peer, PeerAllowedIP, WireGuardInstance
|
from wireguard.models import Peer, PeerAllowedIP, WireGuardInstance
|
||||||
from wireguard_peer.forms import PeerAllowedIPForm, PeerForm
|
from wireguard_peer.forms import PeerAllowedIPForm, PeerNameForm, PeerKeepaliveForm, PeerKeysForm
|
||||||
|
|
||||||
|
|
||||||
def generate_peer_default(wireguard_instance):
|
def generate_peer_default(wireguard_instance):
|
||||||
@@ -184,10 +184,6 @@ def view_wireguard_peer_create(request):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def view_wireguard_peer_manage(request):
|
def view_wireguard_peer_manage(request):
|
||||||
if request.method == 'POST':
|
|
||||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
|
||||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
|
||||||
else:
|
|
||||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
|
||||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||||
user_acl = get_object_or_404(UserAcl, user=request.user)
|
user_acl = get_object_or_404(UserAcl, user=request.user)
|
||||||
@@ -197,6 +193,8 @@ def view_wireguard_peer_manage(request):
|
|||||||
raise Http404
|
raise Http404
|
||||||
current_instance = current_peer.wireguard_instance
|
current_instance = current_peer.wireguard_instance
|
||||||
if request.GET.get('action') == 'delete':
|
if request.GET.get('action') == 'delete':
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||||
if request.GET.get('confirmation') == 'delete':
|
if request.GET.get('confirmation') == 'delete':
|
||||||
current_peer.wireguard_instance.pending_changes = True
|
current_peer.wireguard_instance.pending_changes = True
|
||||||
current_peer.wireguard_instance.save()
|
current_peer.wireguard_instance.save()
|
||||||
@@ -206,28 +204,62 @@ def view_wireguard_peer_manage(request):
|
|||||||
else:
|
else:
|
||||||
messages.warning(request, _('Error deleting peer|Invalid confirmation message. Type "delete" to confirm.'))
|
messages.warning(request, _('Error deleting peer|Invalid confirmation message. Type "delete" to confirm.'))
|
||||||
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
|
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
|
||||||
page_title = _('Update Peer: ') + str(current_peer)
|
page_title = _('Peer Configuration: ') + str(current_peer)
|
||||||
peer_ip_list = current_peer.peerallowedip_set.filter(config_file='server').order_by('priority')
|
peer_ip_list = current_peer.peerallowedip_set.filter(config_file='server').order_by('priority')
|
||||||
peer_client_ip_list = current_peer.peerallowedip_set.filter(config_file='client').order_by('priority')
|
peer_client_ip_list = current_peer.peerallowedip_set.filter(config_file='client').order_by('priority')
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = PeerForm(request.POST, instance=current_peer)
|
|
||||||
if form.is_valid():
|
|
||||||
form.save()
|
|
||||||
messages.success(request, _('Peer updated|Peer updated successfully.'))
|
|
||||||
current_peer.wireguard_instance.pending_changes = True
|
|
||||||
current_peer.wireguard_instance.save()
|
|
||||||
return redirect('/peer/list/?uuid=' + str(current_peer.wireguard_instance.uuid))
|
|
||||||
else:
|
|
||||||
form = PeerForm(instance=current_peer)
|
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer, 'form': form,
|
'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer,
|
||||||
'peer_ip_list': peer_ip_list, 'peer_client_ip_list': peer_client_ip_list
|
'peer_ip_list': peer_ip_list, 'peer_client_ip_list': peer_client_ip_list
|
||||||
}
|
}
|
||||||
return render(request, 'wireguard/wireguard_manage_peer.html', context)
|
return render(request, 'wireguard/wireguard_manage_peer.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_wireguard_peer_edit_field(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||||
|
user_acl = get_object_or_404(UserAcl, user=request.user)
|
||||||
|
|
||||||
|
current_peer = get_object_or_404(Peer, uuid=request.GET.get('peer'))
|
||||||
|
if not user_has_access_to_peer(user_acl, current_peer):
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
group = request.GET.get('group')
|
||||||
|
form_classes = {
|
||||||
|
'name': PeerNameForm,
|
||||||
|
'keepalive': PeerKeepaliveForm,
|
||||||
|
'keys': PeerKeysForm
|
||||||
|
}
|
||||||
|
|
||||||
|
if group not in form_classes:
|
||||||
|
raise Http404
|
||||||
|
|
||||||
|
FormClass = form_classes[group]
|
||||||
|
|
||||||
|
form = FormClass(request.POST or None, instance=current_peer)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
current_peer.wireguard_instance.pending_changes = True
|
||||||
|
current_peer.wireguard_instance.save()
|
||||||
|
messages.success(request, _('Peer updated|Peer updated successfully.'))
|
||||||
|
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
|
||||||
|
|
||||||
|
page_title = _('Edit Peer')
|
||||||
|
if group == 'name':
|
||||||
|
page_title = _('Edit Peer Name')
|
||||||
|
elif group == 'keepalive':
|
||||||
|
page_title = _('Edit Keepalive')
|
||||||
|
elif group == 'keys':
|
||||||
|
page_title = _('Edit Keys')
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'page_title': page_title,
|
||||||
|
'form': form,
|
||||||
|
}
|
||||||
|
return render(request, 'generic_form.html', context)
|
||||||
|
|
||||||
|
|
||||||
def view_manage_ip_address(request):
|
def view_manage_ip_address(request):
|
||||||
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
|
||||||
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ from wgrrd.views import view_rrd_graph
|
|||||||
from wireguard.views import view_apply_db_patches, view_wireguard_manage_instance, view_wireguard_status, \
|
from wireguard.views import view_apply_db_patches, view_wireguard_manage_instance, view_wireguard_status, \
|
||||||
view_server_list, view_server_detail
|
view_server_list, view_server_detail
|
||||||
from wireguard_peer.views import view_manage_ip_address, view_wireguard_peer_list, view_wireguard_peer_manage, \
|
from wireguard_peer.views import view_manage_ip_address, view_wireguard_peer_list, view_wireguard_peer_manage, \
|
||||||
view_wireguard_peer_sort, view_apply_route_template, view_wireguard_peer_create
|
view_wireguard_peer_sort, view_apply_route_template, view_wireguard_peer_create, view_wireguard_peer_edit_field
|
||||||
from wireguard_tools.views import download_config_or_qrcode, export_wireguard_configs, restart_wireguard_interfaces
|
from wireguard_tools.views import download_config_or_qrcode, export_wireguard_configs, restart_wireguard_interfaces
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -57,6 +57,7 @@ urlpatterns = [
|
|||||||
path('peer/sort/', view_wireguard_peer_sort, name='wireguard_peer_sort'),
|
path('peer/sort/', view_wireguard_peer_sort, name='wireguard_peer_sort'),
|
||||||
path('peer/manage/', view_wireguard_peer_manage, name='wireguard_peer_manage'),
|
path('peer/manage/', view_wireguard_peer_manage, name='wireguard_peer_manage'),
|
||||||
path('peer/create/', view_wireguard_peer_create, name='wireguard_peer_create'),
|
path('peer/create/', view_wireguard_peer_create, name='wireguard_peer_create'),
|
||||||
|
path('peer/edit/', view_wireguard_peer_edit_field, name='wireguard_peer_edit_field'),
|
||||||
path('peer/apply_route_template/', view_apply_route_template, name='apply_route_template'),
|
path('peer/apply_route_template/', view_apply_route_template, name='apply_route_template'),
|
||||||
path('peer/manage_ip_address/', view_manage_ip_address, name='manage_ip_address'),
|
path('peer/manage_ip_address/', view_manage_ip_address, name='manage_ip_address'),
|
||||||
path('rrd/graph/', view_rrd_graph, name='rrd_graph'),
|
path('rrd/graph/', view_rrd_graph, name='rrd_graph'),
|
||||||
|
|||||||
Reference in New Issue
Block a user