add route template application functionality for peers

This commit is contained in:
Eduardo Silva
2026-01-22 15:30:42 -03:00
parent d378b62c49
commit 2a61a05499
4 changed files with 129 additions and 5 deletions

View File

@@ -0,0 +1,67 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<div class="card card-primary card-outline">
<div class="card-header">
<h3 class="card-title">{% trans 'Apply Route Template' %}</h3>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-12">
<p>{% trans 'Select a routing template to apply to the peer' %} <strong>{{ current_peer }}</strong>.</p>
{% if current_template %}
<div class="alert alert-info">
{% trans 'Current Active Template:' %} <strong>{{ current_template.name }}</strong>
</div>
{% endif %}
</div>
</div>
<div class="table-responsive">
<table class="table table-hover table-bordered table-striped">
<thead>
<tr>
<th>{% trans 'Template Name' %}</th>
<th>{% trans 'Type' %}</th>
<th>{% trans 'Actions' %}</th>
</tr>
</thead>
<tbody>
{% for template in available_templates %}
<tr {% if template == current_template %}class="table-primary" {% endif %}>
<td>{{ template.name }}</td>
<td>{{ template.get_route_type_display }}</td>
<td>
{% if template != current_template %}
<form method="post" style="display:inline;">
{% csrf_token %}
<input type="hidden" name="template_uuid" value="{{ template.uuid }}">
<button type="submit" class="btn btn-primary btn-sm">{% trans 'Apply' %}</button>
</form>
{% else %}
<button class="btn btn-secondary btn-sm" disabled>{% trans 'Active' %}</button>
<form method="post" style="display:inline;">
{% csrf_token %}
<input type="hidden" name="action" value="unlink">
<button type="submit" class="btn btn-warning btn-sm">{% trans 'Unlink' %}</button>
</form>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center">{% trans 'No routing templates available for this interface.' %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="card-footer">
<a href="/peer/manage/?peer={{ current_peer.uuid }}" class="btn btn-default">{% trans 'Back' %}</a>
</div>
</div>
{% endblock %}

View File

@@ -112,10 +112,14 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
<label> <label>
<i class="fas fa-info-circle" title="AllowedIPs at client configuration file"></i> <i class="fas fa-info-circle" title="{% trans 'AllowedIPs at client configuration file' %}"></i>
{% trans 'Client Routing Configuration' %} {% trans 'Client Routing' %}
</label> </label>
<a class="btn btn-outline-primary btn-xs" href="/peer/manage_ip_address/?peer={{ current_peer.uuid }}&config=client" >{% trans 'Add Client route' %}</a> <div>
<a class="btn btn-outline-info btn-xs" href="/peer/apply_route_template/?peer={{ current_peer.uuid }}" >{% trans 'Apply template' %}</a>
<a class="btn btn-outline-primary btn-xs" href="/peer/manage_ip_address/?peer={{ current_peer.uuid }}&config=client" >{% trans 'Add Client route' %}</a>
</div>
</div> </div>
<div class="d-flex justify-content-between align-items-center border-bottom mb-3"> <div class="d-flex justify-content-between align-items-center border-bottom mb-3">
<p> <p>

View File

@@ -9,6 +9,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from cluster.models import ClusterSettings, Worker from cluster.models import ClusterSettings, Worker
from routing_templates.models import RoutingTemplate
from user_manager.models import UserAcl 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
@@ -283,4 +284,55 @@ def view_manage_ip_address(request):
return render(request, 'wireguard/wireguard_manage_ip.html', { return render(request, 'wireguard/wireguard_manage_ip.html', {
'page_title': page_title, 'form': form, 'current_peer': current_peer, 'current_ip': current_ip 'page_title': page_title, 'form': form, 'current_peer': current_peer, 'current_ip': current_ip
}) })
@login_required
def view_apply_route_template(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
wireguard_instance = current_peer.wireguard_instance
available_templates = RoutingTemplate.objects.filter(wireguard_instance=wireguard_instance)
current_template = current_peer.routing_template
if request.method == 'POST':
if request.POST.get('action') == 'unlink':
current_peer.routing_template = None
current_peer.save()
current_peer.wireguard_instance.pending_changes = True
current_peer.wireguard_instance.save()
messages.success(request, _('Route template unlinked successfully.'))
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
template_uuid = request.POST.get('template_uuid')
if template_uuid:
selected_template = get_object_or_404(RoutingTemplate, uuid=template_uuid)
# Validation
if not selected_template.allow_peer_custom_routes:
if current_peer.peerallowedip_set.filter(config_file='client', priority__gte=1).exists():
messages.error(request, _('Cannot apply template: This template does not allow custom routes, but the peer has custom client routes defined.'))
return redirect('/peer/apply_route_template/?peer=' + str(current_peer.uuid))
current_peer.routing_template = selected_template
current_peer.save()
current_peer.wireguard_instance.pending_changes = True
current_peer.wireguard_instance.save()
messages.success(request, _('Route template applied successfully.'))
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
context = {
'page_title': _('Apply Route Template'),
'current_peer': current_peer,
'available_templates': available_templates,
'current_template': current_template,
}
return render(request, 'wireguard/apply_route_template.html', context)

View File

@@ -38,7 +38,7 @@ from vpn_invite_public.views import view_public_vpn_invite
from wgrrd.views import view_rrd_graph 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
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_wireguard_peer_sort, view_apply_route_template
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 = [
@@ -55,6 +55,7 @@ urlpatterns = [
path('peer/list/', view_wireguard_peer_list, name='wireguard_peer_list'), path('peer/list/', view_wireguard_peer_list, name='wireguard_peer_list'),
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/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'),
path('console/', view_console, name='console'), path('console/', view_console, name='console'),