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',
|
'icon': 'fas fa-chart-line',
|
||||||
'color': '#27ae60'
|
'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',
|
'name': 'Weather Dashboard',
|
||||||
'description': 'Real-time weather information with beautiful visualizations and forecasts.',
|
'description': 'Real-time weather information with beautiful visualizations and forecasts.',
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ class LinkListView(ListView):
|
|||||||
mini_apps = [
|
mini_apps = [
|
||||||
{'name': 'Image Gallery', 'description': 'Browse Images', 'url': 'mini-apps-image-gallery'},
|
{'name': 'Image Gallery', 'description': 'Browse Images', 'url': 'mini-apps-image-gallery'},
|
||||||
{'name': 'TTS', 'description': 'Convert text to speech', 'url': 'mini-apps-tts'},
|
{'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'] = [
|
context['mini_apps'] = [
|
||||||
{**app, 'color': random.choice(colors)}
|
{**app, 'color': random.choice(colors)}
|
||||||
|
|||||||
@@ -57,6 +57,10 @@
|
|||||||
<i class="fas fa-search mr-1.5"></i> Detect Threats
|
<i class="fas fa-search mr-1.5"></i> Detect Threats
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</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' %}"
|
<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">
|
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
|
<i class="fas fa-plus mr-1.5"></i> New Alert Profile
|
||||||
@@ -261,6 +265,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 ─────────────────────────────────────────────────────── -->
|
<!-- ── Banned IPs ─────────────────────────────────────────────────────── -->
|
||||||
<div class="bg-white shadow-sm rounded-lg border border-gray-200 overflow-hidden">
|
<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">
|
<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('alert/<int:pk>/dismiss/', views.DismissAlertView.as_view(), name='nginxmon-dismiss-alert'),
|
||||||
path('ban/<int:pk>/unban/', views.UnbanIPView.as_view(), name='nginxmon-unban'),
|
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
|
# HTMX partials & APIs
|
||||||
path('api/live-logs/', views.LiveLogsPartialView.as_view(), name='nginxmon-live-logs'),
|
path('api/live-logs/', views.LiveLogsPartialView.as_view(), name='nginxmon-live-logs'),
|
||||||
path('api/alerts/', views.AlertsPartialView.as_view(), name='nginxmon-alerts-partial'),
|
path('api/alerts/', views.AlertsPartialView.as_view(), name='nginxmon-alerts-partial'),
|
||||||
|
|||||||
@@ -327,6 +327,47 @@ class UnbanIPView(View):
|
|||||||
return redirect('nginxmon-dashboard')
|
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 ────────────────────────────────────────────────────────
|
# ── Chart & ingest API ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
class ChartDataView(View):
|
class ChartDataView(View):
|
||||||
|
|||||||
Reference in New Issue
Block a user