TODOs
This commit is contained in:
@@ -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 (<code>admin_login_attempts</code>).
|
||||
* Das Dashboard zeigt alle Identitäten sowie UUID-Token. Neue Identitäten erstellt man über <code>?action=identity_create</code>.
|
||||
* Jedes Identity kann beliebige Felder (<code>identity_fields</code>) enthalten. Der Typ kann <code>single</code>, <code>multi</code>, <code>file</code> oder <code>url</code> sein.
|
||||
* Dateien werden pro Identität über das neue Upload-Formular hinzugefügt und landen in <code>www/_files/</code>. Der Upload speichert Dateiname, generierten Zwischennamen und MIME-Type in <code>files</code>.
|
||||
* Dateien werden pro Identität über das neue Upload-Formular hinzugefügt und landen in <code>www/_files/</code>. Der Upload speichert Dateiname, generierten Zwischennamen und MIME-Type in <code>files</code>. Unter dem Formular zeigt das Admin-UI eine Liste der bereits hochgeladenen Dateien inkl. einer Löschoption.
|
||||
* Wenn ein Feld auf Typ <code>file</code> gesetzt ist, zeigt die Auswahl nur Uploads der aktuellen Identität (per <code>files.identity_id</code>). Die ausgewählte Datei-ID wird im Feldwert gespeichert, damit später nur diese Datei angezeigt oder heruntergeladen wird.
|
||||
* UUID-Token (<code>access_tokens</code>) verbinden eine Identität mit einer eindeutigen Zeichenfolge, können optional Auslaufdaten und Notizen erhalten und dürfen **nur einmal** existieren. Tokenrechte (<code>token_permissions</code>) bestimmen, welche Feldschlüssel Besucher:innen sehen.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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') {
|
||||
|
||||
<?php if (!empty($identityFiles)): ?>
|
||||
<h3>Vorhandene Dateien</h3>
|
||||
<?php if ($fileDeleteMessage !== ''): ?>
|
||||
<p style="color:#22c55e; margin-top:.25rem;"><?= htmlspecialchars($fileDeleteMessage) ?></p>
|
||||
<?php endif; ?>
|
||||
<ul>
|
||||
<?php foreach ($identityFiles as $file): ?>
|
||||
<li><?= htmlspecialchars($file['filename']) ?> (ID <?= (int)$file['id'] ?>)</li>
|
||||
<li>
|
||||
<?= htmlspecialchars($file['filename']) ?> (ID <?= (int)$file['id'] ?>)
|
||||
<form method="post" style="display:inline; margin-left:.75rem;">
|
||||
<input type="hidden" name="file_id" value="<?= (int)$file['id'] ?>">
|
||||
<button name="delete_file" type="submit"
|
||||
onclick="return confirm('Datei wirklich löschen?')">Löschen</button>
|
||||
</form>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
@@ -806,4 +871,16 @@ $identities = $sql->get("SELECT * FROM identities ORDER BY id DESC");
|
||||
</html>
|
||||
<?php
|
||||
//TODO einheitliches dunkles design
|
||||
|
||||
//TODO upload filesize vergrößern auf 32MB
|
||||
|
||||
//TODO im bereich UUID bearbeiten sollen files mit dem dateinamen und einem link (target=_blank) dargestellt werden und nicht mit der id
|
||||
|
||||
//TODO prüfen was passiert, wenn mehrere dateien mit dem gleichen dateinamen hochgeladen werden
|
||||
|
||||
//TODO option schaffen eine bestehende datei zu überschreiben ??? bzw prüfen ob das notwendig ist
|
||||
|
||||
//TODO anzeige von einer gelöschten oder leeren datei ausblenden, bei vollzogenem löschvorgang
|
||||
|
||||
//TODO prüfen ob dateien nur mit korrektem uuid herunterladbar sind
|
||||
?>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
This directory stores uploaded files outside the document root.
|
||||
Reference in New Issue
Block a user