From b07a2ee24d93f5271eaad12c75291c163a0f5341 Mon Sep 17 00:00:00 2001 From: Troy grunt Date: Fri, 13 Feb 2026 22:49:06 +0100 Subject: [PATCH] TODOs --- README.md | 2 +- docker-compose.yml | 1 + www/admin.php | 85 +++++++++++++++++++++++++++++++++++++++++++--- www/files/.gitkeep | 1 - 4 files changed, 83 insertions(+), 6 deletions(-) delete mode 100644 www/files/.gitkeep diff --git a/README.md b/README.md index 747fb2c..726d148 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Dieses Projekt stellt eine einfache Verwaltungsoberfläche für digitale Visiten * Login schützt das Dashboard; nach drei gescheiterten Versuchen wird eine IP für eine Stunde gesperrt (admin_login_attempts). * Das Dashboard zeigt alle Identitäten sowie UUID-Token. Neue Identitäten erstellt man über ?action=identity_create. * Jedes Identity kann beliebige Felder (identity_fields) enthalten. Der Typ kann single, multi, file oder url sein. -* Dateien werden pro Identität über das neue Upload-Formular hinzugefügt und landen in www/_files/. Der Upload speichert Dateiname, generierten Zwischennamen und MIME-Type in files. +* Dateien werden pro Identität über das neue Upload-Formular hinzugefügt und landen in www/_files/. Der Upload speichert Dateiname, generierten Zwischennamen und MIME-Type in files. Unter dem Formular zeigt das Admin-UI eine Liste der bereits hochgeladenen Dateien inkl. einer Löschoption. * Wenn ein Feld auf Typ file gesetzt ist, zeigt die Auswahl nur Uploads der aktuellen Identität (per files.identity_id). Die ausgewählte Datei-ID wird im Feldwert gespeichert, damit später nur diese Datei angezeigt oder heruntergeladen wird. * UUID-Token (access_tokens) verbinden eine Identität mit einer eindeutigen Zeichenfolge, können optional Auslaufdaten und Notizen erhalten und dürfen **nur einmal** existieren. Tokenrechte (token_permissions) bestimmen, welche Feldschlüssel Besucher:innen sehen. diff --git a/docker-compose.yml b/docker-compose.yml index 1af2243..0b4ed12 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: - ./www:/var/www/html depends_on: - db + command: ["sh", "-c", "mkdir -p /var/www/html/_files && chown -R www-data:www-data /var/www/html/_files && apache2-foreground"] db: image: mariadb:11 diff --git a/www/admin.php b/www/admin.php index a248594..b7ed9c5 100644 --- a/www/admin.php +++ b/www/admin.php @@ -265,10 +265,30 @@ if ($action === 'identity_edit') { exit('Identität nicht gefunden'); } - $fileUploadErrors = []; - $fileUploadSuccess = 0; + $uploadErrorLabel = function (int $error): string { + return match ($error) { + UPLOAD_ERR_INI_SIZE => 'Datei überschreitet upload_max_filesize', + UPLOAD_ERR_FORM_SIZE => 'Datei überschreitet MAX_FILE_SIZE', + UPLOAD_ERR_PARTIAL => 'Datei wurde nur teilweise hochgeladen', + UPLOAD_ERR_NO_FILE => 'keine Datei ausgewählt', + UPLOAD_ERR_NO_TMP_DIR => 'temporäres Verzeichnis fehlt', + UPLOAD_ERR_CANT_WRITE => 'Datei konnte nicht geschrieben werden', + UPLOAD_ERR_EXTENSION => 'Upload durch eine Erweiterung abgebrochen', + default => 'unbekannter Upload-Fehler', + }; + }; + + $fileUploadErrors = $_SESSION['fileUploadErrors'] ?? []; + unset($_SESSION['fileUploadErrors']); + $fileUploadSuccess = (int)($_SESSION['fileUploadSuccess'] ?? 0); + unset($_SESSION['fileUploadSuccess']); + $fileDeleteMessage = $_SESSION['fileDeleteMessage'] ?? ''; + unset($_SESSION['fileDeleteMessage']); if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $fileUploadErrors = []; + $fileUploadSuccess = 0; + $fileDeleteMessage = ''; if (isset($_POST['upload_files'])) { $filesInput = $_FILES['files'] ?? null; @@ -309,7 +329,11 @@ if ($action === 'identity_edit') { } if ($error !== UPLOAD_ERR_OK) { - $fileUploadErrors[] = sprintf('Fehler beim Hochladen von %s.', $originalName); + $fileUploadErrors[] = sprintf( + 'Fehler beim Hochladen von %s: %s.', + $originalName, + $uploadErrorLabel($error) + ); continue; } @@ -353,6 +377,33 @@ if ($action === 'identity_edit') { } } + if (isset($_POST['delete_file'])) { + $fileId = (int)($_POST['file_id'] ?? 0); + if ($fileId > 0) { + $file = $sql->single( + "SELECT stored_name, filename FROM files WHERE id = ? AND identity_id = ?", + "ii", + [$fileId, $id] + ); + if ($file) { + $diskPath = __DIR__ . '/_files/' . $file['stored_name']; + if (is_file($diskPath)) { + @unlink($diskPath); + } + $sql->set( + "DELETE FROM files WHERE id = ?", + "i", + [$fileId] + ); + $fileDeleteMessage = sprintf('Datei "%s" gelöscht.', $file['filename']); + } else { + $fileUploadErrors[] = 'Datei nicht gefunden oder gehört nicht zu dieser Identität.'; + } + } else { + $fileUploadErrors[] = 'Ungültige Datei.'; + } + } + // Identität umbenennen if (isset($_POST['rename'])) { $sql->set( @@ -404,6 +455,10 @@ if ($action === 'identity_edit') { ); } + $_SESSION['fileUploadErrors'] = $fileUploadErrors; + $_SESSION['fileUploadSuccess'] = $fileUploadSuccess; + $_SESSION['fileDeleteMessage'] = $fileDeleteMessage; + header("Location: admin.php?action=identity_edit&id=$id"); exit; } @@ -523,9 +578,19 @@ if ($action === 'identity_edit') {

Vorhandene Dateien

+ +

+ @@ -806,4 +871,16 @@ $identities = $sql->get("SELECT * FROM identities ORDER BY id DESC"); diff --git a/www/files/.gitkeep b/www/files/.gitkeep deleted file mode 100644 index cd4950f..0000000 --- a/www/files/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -This directory stores uploaded files outside the document root.