diff --git a/expressjs/src/server.js b/expressjs/src/server.js index 60c8378..5d14ce4 100644 --- a/expressjs/src/server.js +++ b/expressjs/src/server.js @@ -224,6 +224,49 @@ function formatCountdown(ts) { return `${minutes}m`; } +function renderFileManagerPage(title, body) { + return ` + +
+ + +Ungültiger Pfad.
')); + return; + } + + let entries; + try { + entries = await fs.promises.readdir(resolved, { withFileTypes: true }); + } catch (err) { + res.status(500).send(renderFileManagerPage('Admin-Dateien', 'Ordner kann nicht gelesen werden.
')); + return; + } + + const parentPath = relativePath ? relativePath.split('/').slice(0, -1).join('/') : ''; + + const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== '_share'); + const files = entries.filter((entry) => !entry.isDirectory() && entry.name !== '_share'); + + const rowForEntry = (entry, isDir) => { + const childPath = relativePath ? `${relativePath}/${entry.name}` : entry.name; + const href = baseUrl(`/admin/files?path=${encodeURIComponent(childPath)}`); + return ` +| Name | +Typ | +Aktionen | +
|---|
Ungültiger Ordnername.
')); + return; + } + const base = resolveAdminPath(relativePath); + if (!base) { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Ungültiger Pfad.
')); + return; + } + const target = path.join(base, name); + await fs.promises.mkdir(target, { recursive: true }); + await logEvent('admin_mkdir', 'admin', { path: path.join(relativePath, name) }); + res.redirect(baseUrl(`/admin/files?path=${encodeURIComponent(relativePath)}`)); +}); + +app.post(`${basePath}/admin/files/upload`, requireAdminPage, upload.single('file'), async (req, res) => { + const relativePath = String(req.body.path || '').replace(/^\/+/, ''); + const base = resolveAdminPath(relativePath); + if (!base) { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Ungültiger Pfad.
')); + return; + } + if (!req.file) { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Keine Datei hochgeladen.
')); + return; + } + const filename = path.basename(req.file.originalname); + if (filename === '_share') { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Ungültiger Dateiname.
')); + return; + } + const target = path.join(base, filename); + try { + await fs.promises.rename(req.file.path, target); + } catch (err) { + if (err.code === 'EXDEV') { + await fs.promises.copyFile(req.file.path, target); + await fs.promises.unlink(req.file.path); + } else { + throw err; + } + } + await logEvent('admin_upload', 'admin', { path: path.join(relativePath, filename) }); + res.redirect(baseUrl(`/admin/files?path=${encodeURIComponent(relativePath)}`)); +}); + +app.post(`${basePath}/admin/files/rename`, requireAdminPage, async (req, res) => { + const relativePath = String(req.body.path || '').replace(/^\/+/, ''); + const newName = String(req.body.newName || '').trim(); + if (!relativePath) { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Root kann nicht umbenannt werden.
')); + return; + } + if (!newName || newName.includes('/') || newName.includes('\\') || newName === '_share') { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Ungültiger neuer Name.
')); + return; + } + const resolved = resolveAdminPath(relativePath); + if (!resolved) { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Ungültiger Pfad.
')); + return; + } + const target = path.join(path.dirname(resolved), newName); + await fs.promises.rename(resolved, target); + await logEvent('admin_rename', 'admin', { from: relativePath, to: path.join(path.dirname(relativePath), newName) }); + const parent = path.dirname(relativePath); + const nextPath = parent === '.' ? '' : parent; + res.redirect(baseUrl(`/admin/files?path=${encodeURIComponent(nextPath)}`)); +}); + +app.post(`${basePath}/admin/files/delete`, requireAdminPage, async (req, res) => { + const relativePath = String(req.body.path || '').replace(/^\/+/, ''); + if (!relativePath) { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Root kann nicht gelöscht werden.
')); + return; + } + const resolved = resolveAdminPath(relativePath); + if (!resolved) { + res.status(400).send(renderFileManagerPage('Admin-Dateien', 'Ungültiger Pfad.
')); + return; + } + await fs.promises.rm(resolved, { recursive: true, force: true }); + await logEvent('admin_delete', 'admin', { path: relativePath }); + const parent = path.dirname(relativePath); + const nextPath = parent === '.' ? '' : parent; + res.redirect(baseUrl(`/admin/files?path=${encodeURIComponent(nextPath)}`)); +}); + 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) {