mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2026-02-20 03:36:16 +00:00
Add peer scheduling profile management functionality
This commit is contained in:
@@ -22,6 +22,9 @@ class ScheduleProfile(models.Model):
|
|||||||
updated = models.DateTimeField(auto_now=True)
|
updated = models.DateTimeField(auto_now=True)
|
||||||
uuid = models.UUIDField(editable=False, default=uuid.uuid4)
|
uuid = models.UUIDField(editable=False, default=uuid.uuid4)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class ScheduleSlot(models.Model):
|
class ScheduleSlot(models.Model):
|
||||||
profile = models.ForeignKey(ScheduleProfile, on_delete=models.CASCADE, related_name="time_interval")
|
profile = models.ForeignKey(ScheduleProfile, on_delete=models.CASCADE, related_name="time_interval")
|
||||||
|
|||||||
@@ -22,6 +22,62 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Peer State -->
|
||||||
|
<div class="form-group border-bottom pb-3">
|
||||||
|
<label>{% trans 'Peer State' %}</label>
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
{% if current_peer.suspended %}
|
||||||
|
<span class="text-danger"><i class="fas fa-pause-circle"></i> {% trans 'Suspended' %}</span>
|
||||||
|
{% if current_peer.suspend_reason %}
|
||||||
|
<small class="text-muted">{{ current_peer.suspend_reason }}</small>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="text-success"><i class="fas fa-check-circle"></i> {% trans 'Active' %}</span>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if peer_scheduling.next_manual_suspend_at %}
|
||||||
|
<small class="text-muted">{% trans 'Scheduled suspend' %}: {{ peer_scheduling.next_manual_suspend_at|date:"Y-m-d H:i" }}</small>
|
||||||
|
{% endif %}
|
||||||
|
{% if peer_scheduling.next_manual_unsuspend_at %}
|
||||||
|
<small class="text-muted">{% trans 'Scheduled unsuspend' %}: {{ peer_scheduling.next_manual_unsuspend_at|date:"Y-m-d H:i" }}</small>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'wireguard_peer_suspend' %}?peer={{ current_peer.uuid }}" class="btn btn-tool">
|
||||||
|
<i class="fas fa-pen"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Peer Schedule State -->
|
||||||
|
<div class="form-group border-bottom pb-3">
|
||||||
|
<label>{% trans 'Peer Schedule' %}</label>
|
||||||
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
{% if peer_scheduling.profile %}
|
||||||
|
<span><i class="fas fa-calendar-alt"></i> {{ peer_scheduling.profile.name }}</span>
|
||||||
|
{% if current_peer.disabled_by_schedule %}
|
||||||
|
<small class="text-danger">{% trans 'Disabled by schedule' %}</small>
|
||||||
|
{% if peer_scheduling.next_scheduled_enable_at %}
|
||||||
|
<small class="text-muted">{% trans 'Next enable' %}: {{ peer_scheduling.next_scheduled_enable_at|date:"Y-m-d H:i" }}</small>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<small class="text-success">{% trans 'Enabled by schedule' %}</small>
|
||||||
|
{% if peer_scheduling.next_scheduled_disable_at %}
|
||||||
|
<small class="text-muted">{% trans 'Next disable' %}: {{ peer_scheduling.next_scheduled_disable_at|date:"Y-m-d H:i" }}</small>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">{% trans 'No profile associated' %}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<a href="{% url 'wireguard_peer_schedule_profile' %}?peer={{ current_peer.uuid }}"
|
||||||
|
class="btn btn-tool">
|
||||||
|
<i class="fas fa-pen"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Persistent Keepalive -->
|
<!-- Persistent Keepalive -->
|
||||||
<div class="form-group border-bottom pb-3">
|
<div class="form-group border-bottom pb-3">
|
||||||
<label>{% trans 'Persistent Keepalive' %}</label>
|
<label>{% trans 'Persistent Keepalive' %}</label>
|
||||||
|
|||||||
@@ -188,3 +188,34 @@ class PeerSuspensionForm(forms.ModelForm):
|
|||||||
raise forms.ValidationError(_('Scheduled unsuspension time must be at least 10 minutes in the future.'))
|
raise forms.ValidationError(_('Scheduled unsuspension time must be at least 10 minutes in the future.'))
|
||||||
|
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
|
class PeerScheduleProfileForm(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'
|
||||||
|
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
Row(Div(Field('profile'), css_class='col-md-12')),
|
||||||
|
Row(
|
||||||
|
Div(
|
||||||
|
FormActions(
|
||||||
|
Submit('save', _('Save'), css_class='btn-primary'),
|
||||||
|
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 = ['profile']
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ 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, PeerNameForm, PeerKeepaliveForm, PeerKeysForm, PeerSuspensionForm
|
from wireguard_peer.forms import PeerAllowedIPForm, PeerNameForm, PeerKeepaliveForm, PeerKeysForm, PeerSuspensionForm, \
|
||||||
|
PeerScheduleProfileForm
|
||||||
|
|
||||||
|
|
||||||
def generate_peer_default(wireguard_instance):
|
def generate_peer_default(wireguard_instance):
|
||||||
@@ -232,9 +233,16 @@ def view_wireguard_peer_manage(request):
|
|||||||
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')
|
||||||
|
|
||||||
|
# Try to get peer scheduling, if it doesn't exist, it will be None
|
||||||
|
try:
|
||||||
|
peer_scheduling = current_peer.schedule
|
||||||
|
except PeerScheduling.DoesNotExist:
|
||||||
|
peer_scheduling = None
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'page_title': page_title, 'current_instance': current_instance, 'current_peer': current_peer,
|
'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,
|
||||||
|
'peer_scheduling': peer_scheduling
|
||||||
}
|
}
|
||||||
return render(request, 'wireguard/wireguard_manage_peer.html', context)
|
return render(request, 'wireguard/wireguard_manage_peer.html', context)
|
||||||
|
|
||||||
@@ -457,3 +465,32 @@ def view_wireguard_peer_suspend(request):
|
|||||||
'form': form,
|
'form': form,
|
||||||
}
|
}
|
||||||
return render(request, 'generic_form.html', context)
|
return render(request, 'generic_form.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_wireguard_peer_schedule_profile(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 = PeerScheduleProfileForm(request.POST or None, instance=peer_scheduling, peer=current_peer)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _('Peer scheduling profile updated successfully.'))
|
||||||
|
current_peer.wireguard_instance.pending_changes = True
|
||||||
|
current_peer.wireguard_instance.save()
|
||||||
|
return redirect('/peer/manage/?peer=' + str(current_peer.uuid))
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'page_title': _('Manage Peer Schedule Profile'),
|
||||||
|
'current_peer': current_peer,
|
||||||
|
'form': form,
|
||||||
|
}
|
||||||
|
return render(request, 'generic_form.html', context)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ from wireguard.views import view_apply_db_patches, view_wireguard_manage_instanc
|
|||||||
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_edit_field, \
|
view_wireguard_peer_sort, view_apply_route_template, view_wireguard_peer_create, view_wireguard_peer_edit_field, \
|
||||||
view_wireguard_peer_suspend
|
view_wireguard_peer_suspend, view_wireguard_peer_schedule_profile
|
||||||
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 = [
|
||||||
@@ -62,6 +62,7 @@ urlpatterns = [
|
|||||||
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/edit/', view_wireguard_peer_edit_field, name='wireguard_peer_edit_field'),
|
||||||
path('peer/suspend/', view_wireguard_peer_suspend, name='wireguard_peer_suspend'),
|
path('peer/suspend/', view_wireguard_peer_suspend, name='wireguard_peer_suspend'),
|
||||||
|
path('peer/schedule_profile/', view_wireguard_peer_schedule_profile, name='wireguard_peer_schedule_profile'),
|
||||||
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