All checks were successful
Build and Publish Docker Image / deploy (push) Successful in 1m38s
- Add `WARPBOX_TRUSTED_PROXIES` configuration to restrict accepted forwarded client IP headers to specific proxy IPs/CIDRs, securing client IP resolution. - Integrate `BanService` into the background cleanup job to automatically purge expired abuse and ban evidence events. - Update documentation with reverse proxy security guidelines and a production systemd deployment guide.
120 lines
5.4 KiB
HTML
120 lines
5.4 KiB
HTML
{{define "admin_users.html"}}{{template "base" .}}{{end}}
|
|
|
|
{{define "content"}}
|
|
<section class="app-shell admin-shell" aria-labelledby="admin-users-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 is-active" 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" 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-users-title">{{.Data.PageTitle}}</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card admin-table-card">
|
|
<div class="card-content">
|
|
<div class="table-header">
|
|
<div>
|
|
<h2>Create invite</h2>
|
|
<p>Copy the generated link and send it manually. SMTP delivery comes later.</p>
|
|
</div>
|
|
</div>
|
|
{{if .Data.LastInviteURL}}
|
|
<div class="copy-field">
|
|
<input type="text" value="{{.Data.LastInviteURL}}" readonly id="invite-url-field" aria-label="Invite link">
|
|
<button class="button button-outline button-sm" type="button"
|
|
onclick="navigator.clipboard.writeText(document.getElementById('invite-url-field').value).then(()=>{this.textContent='Copied!';setTimeout(()=>this.textContent='Copy',2000)})">Copy</button>
|
|
</div>
|
|
{{end}}
|
|
<form class="inline-controls" action="/admin/invites" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
|
<label><span>Email</span><input type="email" name="email" required></label>
|
|
<label><span>Role</span><select name="role"><option value="user">User</option><option value="admin">Admin</option></select></label>
|
|
<button class="button button-primary" type="submit">Create invite</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card admin-table-card">
|
|
<div class="card-content">
|
|
<div class="table-header">
|
|
<h2>Users</h2>
|
|
<p>Disable accounts or generate reset links.</p>
|
|
</div>
|
|
<div class="admin-table-wrap">
|
|
<table class="admin-table">
|
|
<thead>
|
|
<tr>
|
|
<th>User</th>
|
|
<th>Email</th>
|
|
<th>Role</th>
|
|
<th>Status</th>
|
|
<th>Storage</th>
|
|
<th>Today</th>
|
|
<th>Storage backend</th>
|
|
<th>Joined</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Data.Users}}
|
|
<tr>
|
|
<td>{{.Username}}</td>
|
|
<td>{{.Email}}</td>
|
|
<td>{{.Role}}</td>
|
|
<td><span class="badge {{if eq .Status "active"}}badge-active{{else}}badge-disabled{{end}}">{{.Status}}</span></td>
|
|
<td>{{.StorageUsed}} / {{.StorageQuota}}</td>
|
|
<td>{{.DailyUsed}}</td>
|
|
<td>{{.StorageBackend}}</td>
|
|
<td>{{.CreatedAt}}</td>
|
|
<td class="table-actions">
|
|
{{if eq .Status "disabled"}}
|
|
<form action="/admin/users/{{.ID}}/disable?disabled=false" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
<button class="button button-outline button-sm" type="submit">Reactivate</button>
|
|
</form>
|
|
{{else}}
|
|
<form action="/admin/users/{{.ID}}/disable" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
<button class="button button-danger button-sm" type="submit">Disable</button>
|
|
</form>
|
|
{{end}}
|
|
<form action="/admin/users/{{.ID}}/reset" method="post">
|
|
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
|
<button class="button button-outline button-sm" type="submit">Reset link</button>
|
|
</form>
|
|
<a class="button button-outline button-sm" href="/admin/users/{{.ID}}/edit">Edit</a>
|
|
</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr><td colspan="9" class="muted-copy">No users yet.</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
{{end}}
|