extended expressjs admin dashboard
This commit is contained in:
@@ -510,6 +510,7 @@ app.get(`${basePath}/admin/dashboard`, requireAdminPage, async (req, res) => {
|
||||
totalDeletes,
|
||||
lastCleanup,
|
||||
recentLogs,
|
||||
allUploads,
|
||||
] = await Promise.all([
|
||||
get('SELECT COUNT(*) as count FROM uploads'),
|
||||
get('SELECT COALESCE(SUM(size_bytes), 0) as total FROM uploads'),
|
||||
@@ -518,6 +519,7 @@ app.get(`${basePath}/admin/dashboard`, requireAdminPage, async (req, res) => {
|
||||
get('SELECT COUNT(*) as count FROM admin_logs WHERE event IN (?, ?)', ['delete', 'cleanup']),
|
||||
get('SELECT MAX(created_at) as ts FROM admin_logs WHERE event = ?', ['cleanup']),
|
||||
all('SELECT event, owner, detail, created_at FROM admin_logs ORDER BY created_at DESC LIMIT 500'),
|
||||
all('SELECT id, owner, original_name, stored_name, size_bytes, expires_at FROM uploads ORDER BY uploaded_at DESC'),
|
||||
]);
|
||||
|
||||
const stats = `
|
||||
@@ -540,6 +542,33 @@ app.get(`${basePath}/admin/dashboard`, requireAdminPage, async (req, res) => {
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
const adminUploadsRows = allUploads.map((item) => {
|
||||
const fileUrl = `/_share/${item.stored_name}`;
|
||||
return `
|
||||
<tr>
|
||||
<td>${item.owner}</td>
|
||||
<td>
|
||||
<div><strong>${item.original_name}</strong></div>
|
||||
<div class="muted"><a href="${fileUrl}" target="_blank" rel="noopener">${item.stored_name}</a></div>
|
||||
</td>
|
||||
<td>${formatBytes(item.size_bytes)}</td>
|
||||
<td>
|
||||
<div>${formatTimestamp(item.expires_at)}</div>
|
||||
<div class="muted">Noch ${formatCountdown(item.expires_at)}</div>
|
||||
</td>
|
||||
<td class="actions">
|
||||
<form method="post" action="${baseUrl(`/admin/files/${item.id}/delete`)}">
|
||||
<button type="submit" class="secondary">Löschen</button>
|
||||
</form>
|
||||
<form method="post" action="${baseUrl(`/admin/files/${item.id}/extend`)}">
|
||||
<input name="extendHours" placeholder="Stunden hinzufügen" />
|
||||
<button type="submit">Verlängern</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
const body = `
|
||||
<header>
|
||||
<div>
|
||||
@@ -570,10 +599,65 @@ app.get(`${basePath}/admin/dashboard`, requireAdminPage, async (req, res) => {
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>Aktive Uploads</h2>
|
||||
${allUploads.length ? `
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nutzer</th>
|
||||
<th>Datei</th>
|
||||
<th>Größe</th>
|
||||
<th>Läuft ab</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${adminUploadsRows}
|
||||
</tbody>
|
||||
</table>
|
||||
` : '<div class="muted">Keine aktiven Uploads.</div>'}
|
||||
</section>
|
||||
`;
|
||||
res.send(renderPage('Adminübersicht', body));
|
||||
});
|
||||
|
||||
app.post(`${basePath}/admin/files/:id/delete`, requireAdminPage, async (req, res) => {
|
||||
const uploadEntry = await get('SELECT id, stored_path FROM uploads WHERE id = ?', [req.params.id]);
|
||||
if (!uploadEntry) {
|
||||
res.status(404).send(renderPage('Nicht gefunden', '<p class="card">Upload nicht gefunden.</p>'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await fs.promises.unlink(uploadEntry.stored_path);
|
||||
} catch (err) {
|
||||
// Ignore missing files.
|
||||
}
|
||||
await run('DELETE FROM uploads WHERE id = ?', [uploadEntry.id]);
|
||||
await logEvent('delete', 'admin', { id: uploadEntry.id });
|
||||
res.redirect(baseUrl('/admin/dashboard'));
|
||||
});
|
||||
|
||||
app.post(`${basePath}/admin/files/:id/extend`, requireAdminPage, async (req, res) => {
|
||||
const uploadEntry = await get('SELECT id, expires_at FROM uploads WHERE id = ?', [req.params.id]);
|
||||
if (!uploadEntry) {
|
||||
res.status(404).send(renderPage('Nicht gefunden', '<p class="card">Upload nicht gefunden.</p>'));
|
||||
return;
|
||||
}
|
||||
|
||||
const override = parseFloat(req.body.extendHours || '');
|
||||
const extensionSeconds = Number.isFinite(override) && override > 0
|
||||
? Math.round(override * 3600)
|
||||
: uploadTtlSeconds;
|
||||
|
||||
const base = Math.max(uploadEntry.expires_at, Date.now());
|
||||
const nextExpiry = base + extensionSeconds * 1000;
|
||||
await run('UPDATE uploads SET expires_at = ? WHERE id = ?', [nextExpiry, uploadEntry.id]);
|
||||
await logEvent('extend', 'admin', { id: uploadEntry.id, expires_at: nextExpiry });
|
||||
res.redirect(baseUrl('/admin/dashboard'));
|
||||
});
|
||||
|
||||
app.get(`${basePath}/dashboard`, requireAuthPage, async (req, res) => {
|
||||
const uploads = await all(
|
||||
'SELECT id, original_name, stored_name, size_bytes, uploaded_at, expires_at FROM uploads WHERE owner = ? ORDER BY uploaded_at DESC',
|
||||
|
||||
Reference in New Issue
Block a user