mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
Update ban ip form
This commit is contained in:
@@ -40,14 +40,6 @@ class MiniAppsListView(TemplateView):
|
||||
'icon': 'fas fa-chart-line',
|
||||
'color': '#27ae60'
|
||||
},
|
||||
{
|
||||
'name': 'Nginx IP Ban',
|
||||
'description': 'Manage the nginx ingress block list — view, add, and remove banned IPs and CIDR ranges directly from the Kubernetes ConfigMap.',
|
||||
'url': 'mini-apps-ip-ban',
|
||||
'thumbnail': 'https://images.unsplash.com/photo-1614064641938-3bbee52942c7?w=400&h=300&fit=crop',
|
||||
'icon': 'fas fa-ban',
|
||||
'color': '#e74c3c'
|
||||
},
|
||||
{
|
||||
'name': 'Weather Dashboard',
|
||||
'description': 'Real-time weather information with beautiful visualizations and forecasts.',
|
||||
|
||||
@@ -90,7 +90,6 @@ class LinkListView(ListView):
|
||||
mini_apps = [
|
||||
{'name': 'Image Gallery', 'description': 'Browse Images', 'url': 'mini-apps-image-gallery'},
|
||||
{'name': 'TTS', 'description': 'Convert text to speech', 'url': 'mini-apps-tts'},
|
||||
{'name': 'IP Ban', 'description': 'Block IP addresses', 'url': 'mini-apps-ip-ban'},
|
||||
]
|
||||
context['mini_apps'] = [
|
||||
{**app, 'color': random.choice(colors)}
|
||||
|
||||
@@ -57,6 +57,10 @@
|
||||
<i class="fas fa-search mr-1.5"></i> Detect Threats
|
||||
</button>
|
||||
</form>
|
||||
<button onclick="document.getElementById('ip-ban-modal').classList.remove('hidden')"
|
||||
class="inline-flex items-center px-3 py-1.5 bg-red-600 text-white text-xs rounded-md hover:bg-red-700 font-medium">
|
||||
<i class="fas fa-ban mr-1.5"></i> Ban IP
|
||||
</button>
|
||||
<a href="{% url 'nginxmon-profile-create' %}"
|
||||
class="inline-flex items-center px-3 py-1.5 bg-indigo-600 text-white text-xs rounded-md hover:bg-indigo-700 font-medium">
|
||||
<i class="fas fa-plus mr-1.5"></i> New Alert Profile
|
||||
@@ -261,6 +265,49 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── IP Ban Modal ──────────────────────────────────────────────────────── -->
|
||||
<div id="ip-ban-modal" class="hidden fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
onclick="if(event.target===this)this.classList.add('hidden')">
|
||||
<div class="absolute inset-0 bg-black/40"></div>
|
||||
<div class="relative bg-white rounded-xl shadow-2xl w-full max-w-lg">
|
||||
<div class="px-6 py-4 border-b border-gray-100 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="text-sm font-semibold text-gray-900 flex items-center gap-2">
|
||||
<i class="fas fa-ban text-red-500"></i> Ban IP / CIDR
|
||||
</h2>
|
||||
<p class="text-xs text-gray-400 mt-0.5">
|
||||
Adds to <code class="bg-gray-100 px-1 rounded text-xs">block-cidrs-manual</code> ConfigMap.
|
||||
Separate multiple entries with commas or newlines.
|
||||
</p>
|
||||
</div>
|
||||
<button onclick="document.getElementById('ip-ban-modal').classList.add('hidden')"
|
||||
class="text-gray-400 hover:text-gray-600 text-lg leading-none ml-4">×</button>
|
||||
</div>
|
||||
<form method="post" action="{% url 'nginxmon-ip-ban' %}" class="p-6 space-y-4">
|
||||
{% csrf_token %}
|
||||
<textarea name="ips" rows="4" autofocus
|
||||
placeholder="1.2.3.4 5.6.7.0/24 8.8.8.8, 9.9.9.9"
|
||||
class="w-full border border-gray-300 rounded-md px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-red-400 focus:border-transparent resize-none"></textarea>
|
||||
<div class="flex items-center justify-between">
|
||||
<p class="text-xs text-gray-400">
|
||||
<i class="fas fa-info-circle mr-1"></i>Duplicates are skipped automatically.
|
||||
</p>
|
||||
<div class="flex gap-2">
|
||||
<button type="button"
|
||||
onclick="document.getElementById('ip-ban-modal').classList.add('hidden')"
|
||||
class="px-4 py-2 text-xs rounded-md bg-gray-100 text-gray-600 hover:bg-gray-200 font-medium">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="inline-flex items-center px-5 py-2 bg-red-600 text-white text-xs font-medium rounded-md hover:bg-red-700 transition-colors">
|
||||
<i class="fas fa-ban mr-1.5"></i> Ban IPs
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Banned IPs ─────────────────────────────────────────────────────── -->
|
||||
<div class="bg-white shadow-sm rounded-lg border border-gray-200 overflow-hidden">
|
||||
<div class="px-6 py-4 bg-red-50 border-b border-red-200 flex items-center justify-between">
|
||||
|
||||
@@ -20,6 +20,9 @@ urlpatterns = [
|
||||
path('alert/<int:pk>/dismiss/', views.DismissAlertView.as_view(), name='nginxmon-dismiss-alert'),
|
||||
path('ban/<int:pk>/unban/', views.UnbanIPView.as_view(), name='nginxmon-unban'),
|
||||
|
||||
# Manual IP ban form
|
||||
path('actions/ip-ban/', views.IPBanView.as_view(), name='nginxmon-ip-ban'),
|
||||
|
||||
# HTMX partials & APIs
|
||||
path('api/live-logs/', views.LiveLogsPartialView.as_view(), name='nginxmon-live-logs'),
|
||||
path('api/alerts/', views.AlertsPartialView.as_view(), name='nginxmon-alerts-partial'),
|
||||
|
||||
@@ -327,6 +327,47 @@ class UnbanIPView(View):
|
||||
return redirect('nginxmon-dashboard')
|
||||
|
||||
|
||||
class IPBanView(View):
|
||||
"""Manual IP ban form — adds IPs/CIDRs to the k8s ConfigMap and creates BannedIP records."""
|
||||
|
||||
def post(self, request):
|
||||
raw = request.POST.get('ips', '').strip()
|
||||
if not raw:
|
||||
messages.error(request, 'No IPs provided.')
|
||||
return redirect('nginxmon-dashboard')
|
||||
|
||||
new_ips = [
|
||||
ip.strip()
|
||||
for part in raw.replace('\n', ',').split(',')
|
||||
for ip in [part.strip()]
|
||||
if ip
|
||||
]
|
||||
|
||||
try:
|
||||
from links.mini_apps_views import _read_blocked_ips, _write_blocked_ips
|
||||
blocked = _read_blocked_ips()
|
||||
added = 0
|
||||
for ip in new_ips:
|
||||
if ip not in blocked:
|
||||
blocked.append(ip)
|
||||
added += 1
|
||||
BannedIP.objects.get_or_create(
|
||||
ip=ip,
|
||||
defaults=dict(
|
||||
ban_source='manual',
|
||||
reason='Manually banned from dashboard.',
|
||||
request_count=NginxAccessLog.objects.filter(remote_addr=ip).count(),
|
||||
),
|
||||
)
|
||||
_write_blocked_ips(blocked)
|
||||
messages.success(request, f'Banned {added} new IP(s). Total blocked: {len(blocked)}.')
|
||||
except Exception as exc:
|
||||
logger.error('nginxmon IPBanView: %s', exc)
|
||||
messages.error(request, f'Failed to ban IPs: {exc}')
|
||||
|
||||
return redirect('nginxmon-dashboard')
|
||||
|
||||
|
||||
# ── Chart & ingest API ────────────────────────────────────────────────────────
|
||||
|
||||
class ChartDataView(View):
|
||||
|
||||
Reference in New Issue
Block a user