mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2026-02-19 19:26:17 +00:00
Add peer suspension management form and view
This commit is contained in:
@@ -231,9 +231,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-outline-secondary"
|
||||
<a class="btn btn-outline-primary"
|
||||
href="/peer/list/?uuid={{ current_peer.wireguard_instance.uuid }}#peer-{{ current_peer.public_key }}">
|
||||
{% trans 'Back' %}
|
||||
{% trans 'Peer List' %}
|
||||
</a>
|
||||
<a class="btn btn-outline-secondary" href="{% url 'wireguard_peer_suspend' %}?peer={{ current_peer.uuid }}">
|
||||
{% if peer.suspended %}
|
||||
{% trans 'Reactivate' %}
|
||||
{% else %}
|
||||
{% trans 'Suspend' %}
|
||||
{% endif %}
|
||||
</a>
|
||||
<a href='javascript:void(0)' class='btn btn-outline-danger' data-command='delete'
|
||||
onclick='openCommandDialog(this)'>{% trans 'Delete Peer' %}</a>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import ipaddress
|
||||
from datetime import timedelta
|
||||
|
||||
from crispy_forms.bootstrap import FormActions
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Layout, Submit, Button
|
||||
from crispy_forms.layout import Button, Field
|
||||
from crispy_forms.layout import HTML, Layout, Row, Submit, Div
|
||||
from django import forms
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from scheduler.models import PeerScheduling
|
||||
from wireguard.models import NETMASK_CHOICES, Peer, PeerAllowedIP
|
||||
|
||||
|
||||
@@ -108,3 +113,79 @@ class PeerAllowedIPForm(forms.ModelForm):
|
||||
model = PeerAllowedIP
|
||||
fields = ['allowed_ip', 'priority', 'netmask']
|
||||
|
||||
|
||||
class PeerSuspensionForm(forms.ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.peer = kwargs.pop('peer', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_method = 'post'
|
||||
|
||||
if self.peer and self.peer.suspended:
|
||||
suspend_toggle_text = _('Reactivate now')
|
||||
suspend_toggle_action = 'unsuspend_now'
|
||||
else:
|
||||
suspend_toggle_text = _('Suspend now')
|
||||
suspend_toggle_action = 'suspend_now'
|
||||
|
||||
|
||||
self.helper.layout = Layout(
|
||||
Row(Div(Field('next_manual_suspend_at'), css_class='col-md-12')),
|
||||
Row(Div(Field('next_manual_unsuspend_at'), css_class='col-md-12')),
|
||||
Row(Div(Field('manual_suspend_reason'), css_class='col-md-12')),
|
||||
Row(
|
||||
Div(
|
||||
HTML(
|
||||
'<button type="submit" name="action" value="schedule" '
|
||||
'class="btn btn-primary me-2">{}</button>'.format(_("Schedule"))
|
||||
),
|
||||
HTML(
|
||||
'<button type="submit" name="action" value="clear_schedule" '
|
||||
'class="btn btn-primary me-2">{}</button>'.format(_("Clear Schedule"))
|
||||
),
|
||||
HTML(
|
||||
'<button type="submit" name="action" value="{}" '
|
||||
'class="btn btn-primary me-2">{}</button>'.format(
|
||||
suspend_toggle_action,
|
||||
suspend_toggle_text
|
||||
)
|
||||
),
|
||||
HTML(
|
||||
'<a class="btn btn-secondary" href="{}?peer={}">{}</a>'.format(
|
||||
reverse_lazy('wireguard_peer_manage'),
|
||||
self.peer.uuid,
|
||||
_("Back")
|
||||
)
|
||||
),
|
||||
|
||||
css_class='col-md-12')
|
||||
)
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = PeerScheduling
|
||||
fields = ['next_manual_suspend_at', 'next_manual_unsuspend_at', 'manual_suspend_reason']
|
||||
widgets = {
|
||||
'next_manual_suspend_at': forms.DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
|
||||
'next_manual_unsuspend_at': forms.DateTimeInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
|
||||
'manual_suspend_reason': forms.Textarea(attrs={'rows': 3}),
|
||||
}
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
suspend_at = cleaned_data.get('next_manual_suspend_at')
|
||||
unsuspend_at = cleaned_data.get('next_manual_unsuspend_at')
|
||||
|
||||
if suspend_at and unsuspend_at:
|
||||
time_diff = abs((unsuspend_at - suspend_at).total_seconds())
|
||||
if time_diff < 300:
|
||||
raise forms.ValidationError(_('The difference between suspend and unsuspend times must be at least 5 minutes.'))
|
||||
|
||||
min_future_time = timezone.now() + timedelta(minutes=10)
|
||||
if suspend_at and suspend_at < min_future_time:
|
||||
raise forms.ValidationError(_('Scheduled suspension time must be at least 10 minutes in the future.'))
|
||||
|
||||
if unsuspend_at and unsuspend_at < min_future_time:
|
||||
raise forms.ValidationError(_('Scheduled unsuspension time must be at least 10 minutes in the future.'))
|
||||
|
||||
return cleaned_data
|
||||
|
||||
@@ -11,11 +11,12 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from cluster.models import ClusterSettings, Worker
|
||||
from routing_templates.models import RoutingTemplate
|
||||
from scheduler.models import PeerScheduling
|
||||
from user_manager.models import UserAcl
|
||||
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
|
||||
from wireguard.models import Peer, PeerAllowedIP, WireGuardInstance
|
||||
from wireguard_peer.forms import PeerAllowedIPForm, PeerNameForm, PeerKeepaliveForm, PeerKeysForm
|
||||
from wireguard_peer.forms import PeerAllowedIPForm, PeerNameForm, PeerKeepaliveForm, PeerKeysForm, PeerSuspensionForm
|
||||
|
||||
|
||||
def generate_peer_default(wireguard_instance):
|
||||
@@ -393,3 +394,66 @@ def view_apply_route_template(request):
|
||||
}
|
||||
return render(request, 'wireguard/apply_route_template.html', context)
|
||||
|
||||
|
||||
@login_required
|
||||
def view_wireguard_peer_suspend(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
|
||||
|
||||
peer_scheduling, created = PeerScheduling.objects.get_or_create(peer=current_peer)
|
||||
form = PeerSuspensionForm(request.POST or None, instance=peer_scheduling, peer=current_peer)
|
||||
|
||||
if request.method == 'POST':
|
||||
action = request.POST.get('action')
|
||||
manual_suspend_reason = request.POST.get('manual_suspend_reason', '')
|
||||
|
||||
if action == 'schedule':
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
messages.success(request, _('Peer suspension/unsuspension scheduled successfully.'))
|
||||
current_peer.wireguard_instance.pending_changes = True
|
||||
current_peer.wireguard_instance.save()
|
||||
else:
|
||||
messages.error(request, _('Error scheduling peer suspension/unsuspension. Please correct the errors below.'))
|
||||
|
||||
elif action == 'clear_schedule':
|
||||
peer_scheduling.next_manual_suspend_at = None
|
||||
peer_scheduling.next_manual_unsuspend_at = None
|
||||
peer_scheduling.manual_suspend_reason = None
|
||||
peer_scheduling.save()
|
||||
messages.success(request, _('Schedule cleared successfully.'))
|
||||
current_peer.wireguard_instance.pending_changes = True
|
||||
current_peer.wireguard_instance.save()
|
||||
|
||||
elif action == 'suspend_now':
|
||||
current_peer.suspended = True
|
||||
current_peer.suspend_reason = manual_suspend_reason
|
||||
current_peer.save()
|
||||
messages.success(request, _('Peer suspended successfully.'))
|
||||
current_peer.wireguard_instance.pending_changes = True
|
||||
current_peer.wireguard_instance.save()
|
||||
|
||||
elif action == 'unsuspend_now':
|
||||
current_peer.suspended = False
|
||||
current_peer.suspend_reason = ''
|
||||
current_peer.save()
|
||||
messages.success(request, _('Peer reactivated successfully.'))
|
||||
current_peer.wireguard_instance.pending_changes = True
|
||||
current_peer.wireguard_instance.save()
|
||||
else:
|
||||
messages.error(request, _('Invalid action.'))
|
||||
|
||||
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
|
||||
|
||||
context = {
|
||||
'page_title': _('Suspend / Reactivate Peer'),
|
||||
'current_peer': current_peer,
|
||||
'form': form,
|
||||
}
|
||||
return render(request, 'generic_form.html', context)
|
||||
|
||||
@@ -41,7 +41,8 @@ from wgrrd.views import view_rrd_graph
|
||||
from wireguard.views import view_apply_db_patches, view_wireguard_manage_instance, view_wireguard_status, \
|
||||
view_server_list, view_server_detail
|
||||
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_edit_field
|
||||
view_wireguard_peer_sort, view_apply_route_template, view_wireguard_peer_create, view_wireguard_peer_edit_field, \
|
||||
view_wireguard_peer_suspend
|
||||
from wireguard_tools.views import download_config_or_qrcode, export_wireguard_configs, restart_wireguard_interfaces
|
||||
|
||||
urlpatterns = [
|
||||
@@ -60,6 +61,7 @@ urlpatterns = [
|
||||
path('peer/manage/', view_wireguard_peer_manage, name='wireguard_peer_manage'),
|
||||
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/suspend/', view_wireguard_peer_suspend, name='wireguard_peer_suspend'),
|
||||
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('rrd/graph/', view_rrd_graph, name='rrd_graph'),
|
||||
|
||||
Reference in New Issue
Block a user