- Introduce S3-compatible storage backend support using minio-go. - Add configuration options for local storage limits, box limits, and rate limiting. - Implement storage backend selection (local vs S3) for anonymous and registered users. - Add an `/admin/storage` management interface. - Update documentation and environment examples with the new configuration variables.
118 lines
4.9 KiB
HTML
118 lines
4.9 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">Overview</a>
|
|
<a class="sidebar-link" href="/admin/files">Files</a>
|
|
<a class="sidebar-link is-active" href="/admin/users">Users</a>
|
|
<a class="sidebar-link" href="/admin/settings">Settings</a>
|
|
<a class="sidebar-link" href="/admin/storage">Storage</a>
|
|
</nav>
|
|
<hr class="sidebar-sep">
|
|
<nav class="sidebar-nav">
|
|
<a class="sidebar-link" href="/app">My Files</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">Sign out</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}}
|