All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m40s
Enhance the admin panel by introducing visual overview charts for upload and storage trends, along with status bars for system metrics. Additionally, implement pagination for the admin logs view, allowing users to navigate through log entries with configurable page sizes. Corresponding CSS styles have been added for the new charts, metrics grid, and pagination controls.
154 lines
7.9 KiB
HTML
154 lines
7.9 KiB
HTML
{{define "admin_bans.html"}}{{template "base" .}}{{end}}
|
|
|
|
{{define "content"}}
|
|
<section class="app-shell admin-shell" aria-labelledby="admin-bans-title">
|
|
<aside class="app-sidebar">
|
|
<nav class="sidebar-nav">
|
|
<a class="sidebar-link" href="/admin">{{template "icon-dashboard" .}}<span>Overview</span></a>
|
|
<a class="sidebar-link" href="/admin/files">{{template "icon-folder" .}}<span>Files</span></a>
|
|
<a class="sidebar-link" href="/admin/users">{{template "icon-user-circle" .}}<span>Users</span></a>
|
|
<a class="sidebar-link" href="/admin/settings">{{template "icon-settings" .}}<span>Settings</span></a>
|
|
<a class="sidebar-link" href="/admin/storage">{{template "icon-database" .}}<span>Storage</span></a>
|
|
<a class="sidebar-link" href="/admin/logs">{{template "icon-database" .}}<span>Logs</span></a>
|
|
<a class="sidebar-link is-active" href="/admin/bans">{{template "icon-settings" .}}<span>Bans</span></a>
|
|
</nav>
|
|
<hr class="sidebar-sep">
|
|
<nav class="sidebar-nav"><a class="sidebar-link" href="/app">{{template "icon-home-simple" .}}<span>My Files</span></a></nav>
|
|
<hr class="sidebar-sep">
|
|
<form class="sidebar-logout" action="/admin/logout" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
|
<button class="button button-outline" type="submit">{{template "icon-log-out" .}}<span>Sign out</span></button>
|
|
</form>
|
|
</aside>
|
|
|
|
<div class="app-main">
|
|
<div class="admin-header">
|
|
<div>
|
|
<p class="kicker">Operator console</p>
|
|
<h1 id="admin-bans-title">{{.Data.PageTitle}}</h1>
|
|
<p class="muted-copy">Manual IP/CIDR bans and optional automatic abuse protection.</p>
|
|
</div>
|
|
<a class="button button-outline" href="/admin/logs">Open logs</a>
|
|
</div>
|
|
|
|
{{if .Data.Bans.Notice}}<div class="notice">{{.Data.Bans.Notice}}</div>{{end}}
|
|
{{if .Data.Bans.Error}}<div class="notice notice-error">{{.Data.Bans.Error}}</div>{{end}}
|
|
|
|
<div class="metric-grid metric-grid-4">
|
|
<article class="metric-card"><span>Active bans</span><strong>{{.Data.Bans.ActiveCount}}</strong></article>
|
|
<article class="metric-card"><span>Expired</span><strong>{{.Data.Bans.ExpiredCount}}</strong></article>
|
|
<article class="metric-card"><span>Unbanned</span><strong>{{.Data.Bans.UnbannedCount}}</strong></article>
|
|
<article class="metric-card"><span>Auto-ban</span><strong>{{if .Data.Bans.Settings.AutoBanEnabled}}Enabled{{else}}Off{{end}}</strong></article>
|
|
</div>
|
|
|
|
<div class="admin-grid-two">
|
|
<div class="card">
|
|
<div class="card-content">
|
|
<h2>Manual ban</h2>
|
|
<form class="settings-form compact-form" action="/admin/bans" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
|
<label><span>IP or CIDR</span><input name="target" placeholder="203.0.113.10 or 203.0.113.0/24" required></label>
|
|
<label><span>Reason</span><input name="reason" placeholder="Repeated abuse" required></label>
|
|
<label><span>Ban until</span><input type="datetime-local" name="expires_at" required></label>
|
|
<button class="button button-danger" type="submit">Ban target</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-content">
|
|
<h2>Auto-ban settings</h2>
|
|
<form class="settings-form compact-form" action="/admin/bans/settings" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
|
<label class="checkbox-field">
|
|
<input type="checkbox" name="auto_ban_enabled" {{if .Data.Bans.Settings.AutoBanEnabled}}checked{{end}}>
|
|
<span>Enable automatic bans</span>
|
|
</label>
|
|
<label><span>Auto-ban duration (hours)</span><input type="number" min="1" name="auto_ban_duration_hours" value="{{.Data.Bans.Settings.AutoBanDurationHours}}" required></label>
|
|
<label><span>Abuse window (hours)</span><input type="number" min="1" name="abuse_window_hours" value="{{.Data.Bans.Settings.AbuseWindowHours}}" required></label>
|
|
<label><span>Malicious path threshold</span><input type="number" min="1" name="malicious_path_threshold" value="{{.Data.Bans.Settings.MaliciousPathThreshold}}" required></label>
|
|
<label><span>Admin login failures</span><input type="number" min="1" name="admin_login_failure_threshold" value="{{.Data.Bans.Settings.AdminLoginFailureThreshold}}" required></label>
|
|
<label><span>User login failures</span><input type="number" min="1" name="user_login_failure_threshold" value="{{.Data.Bans.Settings.UserLoginFailureThreshold}}" required></label>
|
|
<button class="button button-primary" type="submit">Save auto-ban settings</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card admin-table-card">
|
|
<div class="card-content">
|
|
<div class="table-header">
|
|
<div>
|
|
<h2>Ban records</h2>
|
|
<p>Active records block requests before the normal route handler runs.</p>
|
|
</div>
|
|
</div>
|
|
<form class="logs-filter-card" method="get" action="/admin/bans">
|
|
<label><span>Status</span>
|
|
<select name="status">
|
|
<option value="">All</option>
|
|
<option value="active" {{if eq .Data.Bans.Status "active"}}selected{{end}}>Active</option>
|
|
<option value="expired" {{if eq .Data.Bans.Status "expired"}}selected{{end}}>Expired</option>
|
|
<option value="unbanned" {{if eq .Data.Bans.Status "unbanned"}}selected{{end}}>Unbanned</option>
|
|
</select>
|
|
</label>
|
|
<label><span>Search</span><input name="q" value="{{.Data.Bans.Query}}" placeholder="IP, CIDR, reason"></label>
|
|
<button class="button button-outline" type="submit">Filter</button>
|
|
</form>
|
|
<div class="admin-table-wrap">
|
|
<table class="admin-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Target</th>
|
|
<th>Reason</th>
|
|
<th>Source</th>
|
|
<th>Status</th>
|
|
<th>Expires</th>
|
|
<th>Last match</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Data.Bans.Bans}}
|
|
<tr>
|
|
<td><code>{{.Target}}</code></td>
|
|
<td>{{.Reason}}</td>
|
|
<td>{{.Source}}</td>
|
|
<td><span class="badge">{{.Status}}</span></td>
|
|
<td>{{.ExpiresAt}}</td>
|
|
<td>{{.LastMatched}}</td>
|
|
<td>
|
|
{{if eq .Status "active"}}
|
|
<form action="/admin/bans/{{.ID}}/unban" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
<button class="button button-outline" type="submit">Unban</button>
|
|
</form>
|
|
{{else}}
|
|
<span class="muted-copy">No action</span>
|
|
{{end}}
|
|
</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr><td colspan="7">No bans match this filter.</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card admin-table-card">
|
|
<div class="card-content">
|
|
<h2>Malicious path rules</h2>
|
|
<p class="muted-copy">One case-insensitive substring per line. These rules only create bans when auto-ban is enabled.</p>
|
|
<form class="settings-form compact-form" action="/admin/bans/rules" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
|
<label><span>Patterns</span><textarea name="patterns" rows="10" spellcheck="false">{{.Data.Bans.RulePatterns}}</textarea></label>
|
|
<button class="button button-primary" type="submit">Save rules</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
{{end}}
|