mirror of
https://github.com/eduardogsilva/wireguard_webadmin.git
synced 2026-03-15 13:36:18 +00:00
add app_gateway management views and templates
This commit is contained in:
205
app_gateway/forms.py
Normal file
205
app_gateway/forms.py
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from crispy_forms.helper import FormHelper
|
||||||
|
from crispy_forms.layout import Layout, Submit, HTML, Div
|
||||||
|
from django import forms
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from app_gateway.models import (
|
||||||
|
Application, ApplicationHost, AccessPolicy, ApplicationPolicy, ApplicationRoute
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Application
|
||||||
|
fields = ['name', 'display_name', 'upstream']
|
||||||
|
labels = {
|
||||||
|
'name': _('Name'),
|
||||||
|
'display_name': _('Display Name'),
|
||||||
|
'upstream': _('Upstream'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
cancel_url = kwargs.pop('cancel_url', '#')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.helper = FormHelper()
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
Div(
|
||||||
|
Div('name', css_class='col-md-6'),
|
||||||
|
Div('display_name', css_class='col-md-6'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div('upstream', css_class='col-md-12'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div(
|
||||||
|
Submit('submit', _('Save'), css_class='btn btn-primary'),
|
||||||
|
HTML(f'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
|
||||||
|
css_class='col-12 d-flex justify-content-end gap-2 mt-3'
|
||||||
|
),
|
||||||
|
css_class='row'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
cleaned_data = super().clean()
|
||||||
|
upstream = (cleaned_data.get("upstream") or "").strip()
|
||||||
|
|
||||||
|
if upstream:
|
||||||
|
if " " in upstream:
|
||||||
|
self.add_error("upstream", _("Upstream URL cannot contain spaces."))
|
||||||
|
|
||||||
|
parsed = urlparse(upstream)
|
||||||
|
is_valid = (parsed.scheme in {"http", "https"} and bool(parsed.netloc))
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
|
self.add_error("upstream", _("Enter a valid upstream URL starting with http:// or https://"))
|
||||||
|
|
||||||
|
return cleaned_data
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationHostForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = ApplicationHost
|
||||||
|
fields = ['application', 'hostname']
|
||||||
|
labels = {
|
||||||
|
'application': _('Application'),
|
||||||
|
'hostname': _('Hostname'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
cancel_url = kwargs.pop('cancel_url', '#')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.helper = FormHelper()
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
Div(
|
||||||
|
Div('application', css_class='col-md-6'),
|
||||||
|
Div('hostname', css_class='col-md-6'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div(
|
||||||
|
Submit('submit', _('Save'), css_class='btn btn-primary'),
|
||||||
|
HTML(f'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
|
||||||
|
css_class='col-12 d-flex justify-content-end gap-2 mt-3'
|
||||||
|
),
|
||||||
|
css_class='row'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AccessPolicyForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = AccessPolicy
|
||||||
|
fields = ['name', 'policy_type', 'groups', 'methods']
|
||||||
|
labels = {
|
||||||
|
'name': _('Name'),
|
||||||
|
'policy_type': _('Policy Type'),
|
||||||
|
'groups': _('Allowed Groups'),
|
||||||
|
'methods': _('Authentication Methods'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
cancel_url = kwargs.pop('cancel_url', '#')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.helper = FormHelper()
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
Div(
|
||||||
|
Div('name', css_class='col-md-6'),
|
||||||
|
Div('policy_type', css_class='col-md-6'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div('groups', css_class='col-md-6'),
|
||||||
|
Div('methods', css_class='col-md-6'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div(
|
||||||
|
Submit('submit', _('Save'), css_class='btn btn-primary'),
|
||||||
|
HTML(f'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
|
||||||
|
css_class='col-12 d-flex justify-content-end gap-2 mt-3'
|
||||||
|
),
|
||||||
|
css_class='row'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationPolicyForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = ApplicationPolicy
|
||||||
|
fields = ['application', 'default_policy']
|
||||||
|
labels = {
|
||||||
|
'application': _('Application'),
|
||||||
|
'default_policy': _('Default Policy'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
cancel_url = kwargs.pop('cancel_url', '#')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.helper = FormHelper()
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
Div(
|
||||||
|
Div('application', css_class='col-md-6'),
|
||||||
|
Div('default_policy', css_class='col-md-6'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div(
|
||||||
|
Submit('submit', _('Save'), css_class='btn btn-primary'),
|
||||||
|
HTML(f'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
|
||||||
|
css_class='col-12 d-flex justify-content-end gap-2 mt-3'
|
||||||
|
),
|
||||||
|
css_class='row'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicationRouteForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = ApplicationRoute
|
||||||
|
fields = ['application', 'name', 'path_prefix', 'policy', 'order']
|
||||||
|
labels = {
|
||||||
|
'application': _('Application'),
|
||||||
|
'name': _('Route Name'),
|
||||||
|
'path_prefix': _('Path Prefix'),
|
||||||
|
'policy': _('Policy'),
|
||||||
|
'order': _('Priority Order'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
cancel_url = kwargs.pop('cancel_url', '#')
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.helper = FormHelper()
|
||||||
|
self.helper.layout = Layout(
|
||||||
|
Div(
|
||||||
|
Div('application', css_class='col-md-6'),
|
||||||
|
Div('name', css_class='col-md-6'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div('path_prefix', css_class='col-md-8'),
|
||||||
|
Div('order', css_class='col-md-4'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div('policy', css_class='col-md-12'),
|
||||||
|
css_class='row'
|
||||||
|
),
|
||||||
|
Div(
|
||||||
|
Div(
|
||||||
|
Submit('submit', _('Save'), css_class='btn btn-primary'),
|
||||||
|
HTML(f'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
|
||||||
|
css_class='col-12 d-flex justify-content-end gap-2 mt-3'
|
||||||
|
),
|
||||||
|
css_class='row'
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.12 on 2026-03-12 14:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app_gateway', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='application',
|
||||||
|
name='display_name',
|
||||||
|
field=models.CharField(blank=True, max_length=128),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.12 on 2026-03-12 14:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app_gateway', '0002_alter_application_display_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='application',
|
||||||
|
name='display_name',
|
||||||
|
field=models.CharField(max_length=128),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.12 on 2026-03-12 14:52
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app_gateway', '0003_alter_application_display_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='application',
|
||||||
|
name='display_name',
|
||||||
|
field=models.CharField(blank=True, max_length=128),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -8,7 +8,7 @@ from gatekeeper.models import GatekeeperGroup, AuthMethod
|
|||||||
|
|
||||||
class Application(models.Model):
|
class Application(models.Model):
|
||||||
name = models.SlugField(max_length=64, unique=True)
|
name = models.SlugField(max_length=64, unique=True)
|
||||||
display_name = models.CharField(max_length=128)
|
display_name = models.CharField(max_length=128, blank=True)
|
||||||
upstream = models.CharField(max_length=255, help_text=_("Upstream address, e.g.: http://10.188.18.27:3000"))
|
upstream = models.CharField(max_length=255, help_text=_("Upstream address, e.g.: http://10.188.18.27:3000"))
|
||||||
|
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
@@ -16,7 +16,10 @@ class Application(models.Model):
|
|||||||
uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
|
uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.display_name
|
if self.display_name:
|
||||||
|
return f"{self.display_name} ({self.name})"
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['name']
|
ordering = ['name']
|
||||||
|
|||||||
28
app_gateway/urls.py
Normal file
28
app_gateway/urls.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from app_gateway import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
# Main Dashboard / List
|
||||||
|
path('', views.view_app_gateway_list, name='app_gateway_list'),
|
||||||
|
|
||||||
|
# Applications
|
||||||
|
path('application/manage/', views.view_manage_application, name='manage_application'),
|
||||||
|
path('application/delete/', views.view_delete_application, name='delete_application'),
|
||||||
|
|
||||||
|
# Application Hosts
|
||||||
|
path('host/manage/', views.view_manage_application_host, name='manage_application_host'),
|
||||||
|
path('host/delete/', views.view_delete_application_host, name='delete_application_host'),
|
||||||
|
|
||||||
|
# Access Policies
|
||||||
|
path('policy/manage/', views.view_manage_access_policy, name='manage_access_policy'),
|
||||||
|
path('policy/delete/', views.view_delete_access_policy, name='delete_access_policy'),
|
||||||
|
|
||||||
|
# Application Default Policies
|
||||||
|
path('app_policy/manage/', views.view_manage_application_policy, name='manage_application_policy'),
|
||||||
|
path('app_policy/delete/', views.view_delete_application_policy, name='delete_application_policy'),
|
||||||
|
|
||||||
|
# Application Routes
|
||||||
|
path('route/manage/', views.view_manage_application_route, name='manage_application_route'),
|
||||||
|
path('route/delete/', views.view_delete_application_route, name='delete_application_route'),
|
||||||
|
]
|
||||||
@@ -1 +1,309 @@
|
|||||||
# Create your views here.
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.shortcuts import render, get_object_or_404, redirect
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
from app_gateway.forms import (
|
||||||
|
ApplicationForm, ApplicationHostForm, AccessPolicyForm,
|
||||||
|
ApplicationPolicyForm, ApplicationRouteForm
|
||||||
|
)
|
||||||
|
from app_gateway.models import (
|
||||||
|
Application, ApplicationHost, AccessPolicy, ApplicationPolicy, ApplicationRoute
|
||||||
|
)
|
||||||
|
from user_manager.models import UserAcl
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_app_gateway_list(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
applications = Application.objects.all().order_by('name')
|
||||||
|
hosts = ApplicationHost.objects.all().order_by('hostname')
|
||||||
|
access_policies = AccessPolicy.objects.all().order_by('name')
|
||||||
|
app_policies = ApplicationPolicy.objects.all().order_by('application__name')
|
||||||
|
routes = ApplicationRoute.objects.all().order_by('application__name', 'order', 'path_prefix')
|
||||||
|
|
||||||
|
tab = request.GET.get('tab', 'applications')
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'applications': applications,
|
||||||
|
'hosts': hosts,
|
||||||
|
'access_policies': access_policies,
|
||||||
|
'app_policies': app_policies,
|
||||||
|
'routes': routes,
|
||||||
|
'active_tab': tab,
|
||||||
|
}
|
||||||
|
return render(request, 'app_gateway/app_gateway_list.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_manage_application(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application_uuid = request.GET.get('uuid')
|
||||||
|
|
||||||
|
if application_uuid:
|
||||||
|
application = get_object_or_404(Application, uuid=application_uuid)
|
||||||
|
title = _('Edit Application')
|
||||||
|
else:
|
||||||
|
application = None
|
||||||
|
title = _('Create Application')
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=applications'
|
||||||
|
|
||||||
|
form = ApplicationForm(request.POST or None, instance=application, cancel_url=cancel_url)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _('Application saved successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'title': title,
|
||||||
|
'page_title': title,
|
||||||
|
}
|
||||||
|
return render(request, 'generic_form.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_delete_application(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application = get_object_or_404(Application, uuid=request.GET.get('uuid'))
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=applications'
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
application.delete()
|
||||||
|
messages.success(request, _('Application deleted successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'application': application,
|
||||||
|
'title': _('Delete Application'),
|
||||||
|
'cancel_url': cancel_url,
|
||||||
|
'text': _('Are you sure you want to delete the application "%(name)s"?') % {'name': application.display_name}
|
||||||
|
}
|
||||||
|
return render(request, 'generic_delete_confirmation.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_manage_application_host(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application_host_uuid = request.GET.get('uuid')
|
||||||
|
|
||||||
|
if application_host_uuid:
|
||||||
|
application_host = get_object_or_404(ApplicationHost, uuid=application_host_uuid)
|
||||||
|
title = _('Edit Application Host')
|
||||||
|
else:
|
||||||
|
application_host = None
|
||||||
|
title = _('Add Application Host')
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=hosts'
|
||||||
|
|
||||||
|
form = ApplicationHostForm(request.POST or None, instance=application_host, cancel_url=cancel_url)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _('Application Host saved successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'title': title,
|
||||||
|
'page_title': title,
|
||||||
|
}
|
||||||
|
return render(request, 'generic_form.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_delete_application_host(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application_host = get_object_or_404(ApplicationHost, uuid=request.GET.get('uuid'))
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=hosts'
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
application_host.delete()
|
||||||
|
messages.success(request, _('Application Host deleted successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'application_host': application_host,
|
||||||
|
'title': _('Delete Application Host'),
|
||||||
|
'cancel_url': cancel_url,
|
||||||
|
'text': _('Are you sure you want to delete the host "%(hostname)s"?') % {'hostname': application_host.hostname}
|
||||||
|
}
|
||||||
|
return render(request, 'generic_delete_confirmation.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_manage_access_policy(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
access_policy_uuid = request.GET.get('uuid')
|
||||||
|
|
||||||
|
if access_policy_uuid:
|
||||||
|
access_policy = get_object_or_404(AccessPolicy, uuid=access_policy_uuid)
|
||||||
|
title = _('Edit Access Policy')
|
||||||
|
else:
|
||||||
|
access_policy = None
|
||||||
|
title = _('Create Access Policy')
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=policies'
|
||||||
|
|
||||||
|
form = AccessPolicyForm(request.POST or None, instance=access_policy, cancel_url=cancel_url)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _('Access Policy saved successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'title': title,
|
||||||
|
'page_title': title,
|
||||||
|
}
|
||||||
|
return render(request, 'generic_form.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_delete_access_policy(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
access_policy = get_object_or_404(AccessPolicy, uuid=request.GET.get('uuid'))
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=policies'
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
access_policy.delete()
|
||||||
|
messages.success(request, _('Access Policy deleted successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'access_policy': access_policy,
|
||||||
|
'title': _('Delete Access Policy'),
|
||||||
|
'cancel_url': cancel_url,
|
||||||
|
'text': _('Are you sure you want to delete the access policy "%(name)s"?') % {'name': access_policy.name}
|
||||||
|
}
|
||||||
|
return render(request, 'generic_delete_confirmation.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_manage_application_policy(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application_policy_uuid = request.GET.get('uuid')
|
||||||
|
|
||||||
|
if application_policy_uuid:
|
||||||
|
application_policy = get_object_or_404(ApplicationPolicy, uuid=application_policy_uuid)
|
||||||
|
title = _('Edit Application Default Policy')
|
||||||
|
else:
|
||||||
|
application_policy = None
|
||||||
|
title = _('Set Application Default Policy')
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=applications'
|
||||||
|
|
||||||
|
|
||||||
|
form = ApplicationPolicyForm(request.POST or None, instance=application_policy, cancel_url=cancel_url)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _('Application Default Policy saved successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'title': title,
|
||||||
|
'page_title': title,
|
||||||
|
}
|
||||||
|
return render(request, 'generic_form.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_delete_application_policy(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application_policy = get_object_or_404(ApplicationPolicy, uuid=request.GET.get('uuid'))
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=applications'
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
application_policy.delete()
|
||||||
|
messages.success(request, _('Application Default Policy deleted successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'application_policy': application_policy,
|
||||||
|
'title': _('Delete Application Default Policy'),
|
||||||
|
'cancel_url': cancel_url,
|
||||||
|
'text': _('Are you sure you want to remove the default policy for "%(name)s"?') % {
|
||||||
|
'name': application_policy.application.display_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return render(request, 'generic_delete_confirmation.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_manage_application_route(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application_route_uuid = request.GET.get('uuid')
|
||||||
|
|
||||||
|
if application_route_uuid:
|
||||||
|
application_route = get_object_or_404(ApplicationRoute, uuid=application_route_uuid)
|
||||||
|
title = _('Edit Application Route')
|
||||||
|
else:
|
||||||
|
application_route = None
|
||||||
|
title = _('Add Application Route')
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=routes'
|
||||||
|
|
||||||
|
form = ApplicationRouteForm(request.POST or None, instance=application_route, cancel_url=cancel_url)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _('Application Route saved successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'title': title,
|
||||||
|
'page_title': title,
|
||||||
|
}
|
||||||
|
return render(request, 'generic_form.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def view_delete_application_route(request):
|
||||||
|
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
|
||||||
|
return render(request, 'access_denied.html', {'page_title': _('Access Denied')})
|
||||||
|
|
||||||
|
application_route = get_object_or_404(ApplicationRoute, uuid=request.GET.get('uuid'))
|
||||||
|
|
||||||
|
cancel_url = reverse('app_gateway_list') + '?tab=routes'
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
application_route.delete()
|
||||||
|
messages.success(request, _('Application Route deleted successfully.'))
|
||||||
|
return redirect(cancel_url)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'application_route': application_route,
|
||||||
|
'title': _('Delete Application Route'),
|
||||||
|
'cancel_url': cancel_url,
|
||||||
|
'text': _('Are you sure you want to delete the route "%(name)s" (%(path)s)?') % {
|
||||||
|
'name': application_route.name,
|
||||||
|
'path': application_route.path_prefix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return render(request, 'generic_delete_confirmation.html', context)
|
||||||
|
|||||||
254
templates/app_gateway/app_gateway_list.html
Normal file
254
templates/app_gateway/app_gateway_list.html
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="card card-primary card-outline">
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if active_tab == 'applications' or active_tab == 'hosts' %}active{% endif %}"
|
||||||
|
href="{% url 'app_gateway_list' %}?tab=applications" role="tab">
|
||||||
|
{% trans 'Applications' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if active_tab == 'policies' %}active{% endif %}"
|
||||||
|
href="{% url 'app_gateway_list' %}?tab=policies" role="tab">
|
||||||
|
{% trans 'Access Policies' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if active_tab == 'routes' %}active{% endif %}"
|
||||||
|
href="{% url 'app_gateway_list' %}?tab=routes" role="tab">
|
||||||
|
{% trans 'Routes' %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content mt-4">
|
||||||
|
|
||||||
|
{% if active_tab == 'applications' or active_tab == 'hosts' %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="btn-group mb-3">
|
||||||
|
<a href="{% url 'app_gateway_list' %}?tab=applications"
|
||||||
|
class="btn {% if active_tab == 'applications' %}btn-primary{% else %}btn-outline-primary{% endif %}">
|
||||||
|
{% trans 'Applications' %}
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'app_gateway_list' %}?tab=hosts"
|
||||||
|
class="btn {% if active_tab == 'hosts' %}btn-primary{% else %}btn-outline-primary{% endif %}">
|
||||||
|
{% trans 'Hosts' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if active_tab == 'applications' %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<a href="{% url 'manage_application' %}" class="btn btn-outline-primary btn-sm">
|
||||||
|
<i class="fas fa-plus"></i> {% trans 'Add Application' %}
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'manage_application_policy' %}" class="btn btn-outline-secondary btn-sm">
|
||||||
|
<i class="fas fa-shield-alt"></i> {% trans 'Set Default Policy' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if applications %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Name' %}</th>
|
||||||
|
<th>{% trans 'Display Name' %}</th>
|
||||||
|
<th>{% trans 'Upstream' %}</th>
|
||||||
|
<th>{% trans 'Default Policy' %}</th>
|
||||||
|
<th>{% trans 'Actions' %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for app in applications %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ app.name }}</td>
|
||||||
|
<td>{{ app.display_name }}</td>
|
||||||
|
<td><code>{{ app.upstream }}</code></td>
|
||||||
|
<td>
|
||||||
|
{% if app.default_policy_config %}
|
||||||
|
<span class="badge badge-info">{{ app.default_policy_config.default_policy.name }}</span>
|
||||||
|
<a href="{% url 'manage_application_policy' %}?uuid={{ app.default_policy_config.uuid }}"
|
||||||
|
class="btn btn-sm btn-outline-secondary btn-xs" title="{% trans 'Edit Default Policy' %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'delete_application_policy' %}?uuid={{ app.default_policy_config.uuid }}"
|
||||||
|
class="btn btn-sm btn-outline-danger btn-xs" title="{% trans 'Remove Default Policy' %}">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">{% trans 'Not set' %}</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td style="width: 15%">
|
||||||
|
<a href="{% url 'manage_application' %}?uuid={{ app.uuid }}"
|
||||||
|
class="btn btn-sm btn-info" title="{% trans 'Edit' %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'delete_application' %}?uuid={{ app.uuid }}"
|
||||||
|
class="btn btn-sm btn-danger" title="{% trans 'Delete' %}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
{% trans 'No Applications found.' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% elif active_tab == 'hosts' %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<a href="{% url 'manage_application_host' %}" class="btn btn-outline-primary btn-sm">
|
||||||
|
<i class="fas fa-plus"></i> {% trans 'Add Host' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if hosts %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Hostname' %}</th>
|
||||||
|
<th>{% trans 'Application' %}</th>
|
||||||
|
<th>{% trans 'Actions' %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for host in hosts %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ host.hostname }}</td>
|
||||||
|
<td>{{ host.application.display_name }}</td>
|
||||||
|
<td style="width: 15%">
|
||||||
|
<a href="{% url 'manage_application_host' %}?uuid={{ host.uuid }}"
|
||||||
|
class="btn btn-sm btn-info" title="{% trans 'Edit' %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'delete_application_host' %}?uuid={{ host.uuid }}"
|
||||||
|
class="btn btn-sm btn-danger" title="{% trans 'Delete' %}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
{% trans 'No Hosts found.' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% elif active_tab == 'policies' %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<a href="{% url 'manage_access_policy' %}" class="btn btn-outline-primary btn-sm">
|
||||||
|
<i class="fas fa-plus"></i> {% trans 'Add Access Policy' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if access_policies %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Name' %}</th>
|
||||||
|
<th>{% trans 'Policy Type' %}</th>
|
||||||
|
<th>{% trans 'Groups' %}</th>
|
||||||
|
<th>{% trans 'Auth Methods' %}</th>
|
||||||
|
<th>{% trans 'Actions' %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for policy in access_policies %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ policy.name }}</td>
|
||||||
|
<td>{{ policy.get_policy_type_display }}</td>
|
||||||
|
<td>{{ policy.groups.count }}</td>
|
||||||
|
<td>{{ policy.methods.count }}</td>
|
||||||
|
<td style="width: 15%">
|
||||||
|
<a href="{% url 'manage_access_policy' %}?uuid={{ policy.uuid }}"
|
||||||
|
class="btn btn-sm btn-info" title="{% trans 'Edit' %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'delete_access_policy' %}?uuid={{ policy.uuid }}"
|
||||||
|
class="btn btn-sm btn-danger" title="{% trans 'Delete' %}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
{% trans 'No Access Policies found.' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% elif active_tab == 'routes' %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<a href="{% url 'manage_application_route' %}" class="btn btn-outline-primary btn-sm">
|
||||||
|
<i class="fas fa-plus"></i> {% trans 'Add Route' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if routes %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Application' %}</th>
|
||||||
|
<th>{% trans 'Route Name' %}</th>
|
||||||
|
<th>{% trans 'Path Prefix' %}</th>
|
||||||
|
<th>{% trans 'Policy' %}</th>
|
||||||
|
<th>{% trans 'Order' %}</th>
|
||||||
|
<th>{% trans 'Actions' %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for route in routes %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ route.application.display_name }}</td>
|
||||||
|
<td>{{ route.name }}</td>
|
||||||
|
<td><code>{{ route.path_prefix }}</code></td>
|
||||||
|
<td>{{ route.policy.name }}</td>
|
||||||
|
<td>{{ route.order }}</td>
|
||||||
|
<td style="width: 15%">
|
||||||
|
<a href="{% url 'manage_application_route' %}?uuid={{ route.uuid }}"
|
||||||
|
class="btn btn-sm btn-info" title="{% trans 'Edit' %}">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'delete_application_route' %}?uuid={{ route.uuid }}"
|
||||||
|
class="btn btn-sm btn-danger" title="{% trans 'Delete' %}">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">
|
||||||
|
{% trans 'No Routes found.' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -23,6 +23,7 @@ urlpatterns = [
|
|||||||
path('peer/', include('wireguard_peer.urls')),
|
path('peer/', include('wireguard_peer.urls')),
|
||||||
path('routing-templates/', include('routing_templates.urls')),
|
path('routing-templates/', include('routing_templates.urls')),
|
||||||
path('gatekeeper/', include('gatekeeper.urls')),
|
path('gatekeeper/', include('gatekeeper.urls')),
|
||||||
|
path('app_gateway/', include('app_gateway.urls')),
|
||||||
path('scheduler/', include('scheduler.urls')),
|
path('scheduler/', include('scheduler.urls')),
|
||||||
path('server/', include('wireguard.urls')),
|
path('server/', include('wireguard.urls')),
|
||||||
path('tools/', include('wireguard_tools.urls')),
|
path('tools/', include('wireguard_tools.urls')),
|
||||||
|
|||||||
Reference in New Issue
Block a user