From 7c5790e8563e2ef862a2c892e6558ab74acc2bc6 Mon Sep 17 00:00:00 2001 From: Erik Thiele Date: Sat, 23 May 2026 23:32:00 +0200 Subject: [PATCH] Version 1.6 - Strato Verzeichnis unterhalb tc-ingelfingen --- README.md | 21 ++++++++++++++------- config.php | 4 ++-- httpdocs/app/bootstrap.php | 36 +++++++++++++++++++++++++++++++++--- httpdocs/app/views.php | 30 +++++++++++++++--------------- httpdocs/index.php | 6 +++--- httpdocs/install.php | 4 ++-- 6 files changed, 69 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 3080b30..10bf0a4 100644 --- a/README.md +++ b/README.md @@ -23,27 +23,31 @@ Strato-taugliche PHP-Webanwendung für die Arbeitszeiterfassung des TC Ingelfing - Separater CSV-Export für alle Stundenbuchungen - SQL-Dump-Export und SQL-Dump-Wiederherstellung für vollständige App-Backups - Separater CSV-Export der Logansicht für Administratoren +- Admin-Funktion zum Löschen der Audit-Logeinträge - Admin-Funktion zum Zurücksetzen aller Arbeitsstunden auf 0 - Tabler CSS via CDN für UI, Cards, Tabellen und Formulare ## Strato-Setup -1. Inhalt von `httpdocs/` auf das Strato-Webverzeichnis hochladen -2. Optional diese Umgebungsvariablen oder Konfigurationswerte setzen: +1. Inhalt von `httpdocs/` in das Webverzeichnis der App hochladen +2. Wenn die App in einem Unterordner wie `/arbeitsstunden/` läuft, muss genau dieser Ordner das Webroot der App enthalten +3. `config.php` nicht in `httpdocs/`, sondern eine Ebene darüber ablegen +4. Optional diese Umgebungsvariablen oder Konfigurationswerte setzen: - `DB_HOST` - `DB_NAME` - `DB_USER` - `DB_PASS` - `SETUP_KEY` optional, schützt die Ersteinrichtung -3. PHP 8.1+ und `pdo_mysql` aktivieren +5. PHP 8.1+ und `pdo_mysql` aktivieren ## Strato Schritte 1. DB in Strato anlegen -2. `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS` setzen -3. `httpdocs/install.php` öffnen und erstes Admin-Konto anlegen -4. Danach mit dem neuen Admin einloggen -5. Falls keine DB konfiguriert ist, nutzt die App Demo-Zugänge nur zum Anzeigen +2. `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS` setzen oder `config.php` oberhalb des Webroots anlegen +3. Dateien aus `httpdocs/` in den Zielordner der App hochladen, z. B. `https://tc-ingelfingen.de/arbeitsstunden/` +4. `install.php` über den App-Pfad öffnen, z. B. `/arbeitsstunden/install.php`, und erstes Admin-Konto anlegen +5. Danach mit dem neuen Admin einloggen +6. Falls keine DB konfiguriert ist, nutzt die App Demo-Zugänge nur zum Anzeigen ## Datenbank @@ -88,6 +92,7 @@ Die Anwendung ist so aufgebaut, dass sie mit oder ohne DB läuft. Bei gesetzter - Alle Arbeitsstunden auf 0 zurücksetzen - Logansicht mit 50 Einträgen pro Seite - Logansicht als CSV exportieren + - Audit-Logeinträge direkt in der Administration löschen - Audit-Log für Verwaltungsaktionen sowie Login und Logout ## Listen Und Paginierung @@ -166,6 +171,7 @@ Hinweis: - Die aktuelle Implementierung nutzt PHP `mail()` fuer den Versand. - Wenn das Hosting E-Mails direkt versenden kann, funktioniert der Passwort-Reset auch ohne vollstaendige SMTP-Implementierung. - Die Datei `config.php` sollte nicht in `httpdocs/`, sondern im Projektwurzelverzeichnis liegen. +- Bei einem Deployment in einem Unterordner wie `/arbeitsstunden/` liegt `config.php` eine Ebene über diesem Webroot. ## Ersteinrichtung @@ -185,6 +191,7 @@ Für die Weitergabe an Anwender stehen folgende Anleitungen bereit: - `httpdocs/install.php` Ersteinrichtung - `httpdocs/app/bootstrap.php` DB, Login und Business-Logik - `httpdocs/app/views.php` Tabler-UI +- `config.php` lokale Konfiguration oberhalb des Webroots - `config.php.example` Vorlage für DB- und Mail-Konfiguration - `ANLEITUNG_MITGLIEDER.md` Handout für Mitglieder - `ANLEITUNG_BEARBEITER.md` Handout für Bearbeiter diff --git a/config.php b/config.php index a2a1a1a..ffbadd6 100644 --- a/config.php +++ b/config.php @@ -1,9 +1,9 @@ 'OpenCode', + 'author' => 'Erik Thiele', 'copyright' => 'Copyright 2026 TC-Ingelfingen', - 'app_version' => '1.0.0', + 'app_version' => '1.6.0', 'db' => [ 'host' => 'database-5020507124.webspace-host.com', 'name' => 'dbs15701183', diff --git a/httpdocs/app/bootstrap.php b/httpdocs/app/bootstrap.php index 1e0c3d8..1888f02 100644 --- a/httpdocs/app/bootstrap.php +++ b/httpdocs/app/bootstrap.php @@ -115,6 +115,26 @@ function appUrl(): string return $scheme . '://' . $host; } +function basePath(): string +{ + $scriptName = $_SERVER['SCRIPT_NAME'] ?? '/index.php'; + $dir = rtrim(str_replace('\\', '/', dirname($scriptName)), '/'); + return $dir === '' ? '' : $dir; +} + +function appPath(string $path = ''): string +{ + $base = basePath(); + if ($path === '') { + return $base === '' ? '/' : $base . '/'; + } + if ($path[0] === '?') { + return ($base === '' ? '/' : $base . '/') . $path; + } + $path = ltrim($path, '/'); + return $base === '' ? '/' . $path : $base . '/' . $path; +} + function sendPasswordResetMail(array $smtpConfig, string $toEmail, string $resetUrl): bool { if (($smtpConfig['from_email'] ?? '') === '') { @@ -497,7 +517,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { addAuditLog($pdo, (int)$found['id'], 'Anmeldung erfolgreich.'); session_regenerate_id(true); $_SESSION['user'] = ['id' => (int)$found['id'], 'firstname' => $found['firstname'] ?? '', 'lastname' => $found['lastname'] ?? '', 'name' => displayName($found), 'email' => $found['email'], 'role' => $found['role']]; - header('Location: /?page=dashboard'); + header('Location: ' . appPath('?page=home')); exit; } $error = 'Login fehlgeschlagen.'; @@ -557,7 +577,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $stmt->execute([(int)$resetRow['user_id']]); addAuditLog($pdo, (int)$resetRow['user_id'], 'Passwort über Reset-Link neu gesetzt.'); $_SESSION['login_notice'] = 'Passwort erfolgreich zurueckgesetzt. Bitte anmelden.'; - header('Location: /?page=login'); + header('Location: ' . appPath('?page=login')); exit; } } @@ -827,6 +847,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $error = 'Log-Export ist ohne Datenbank nicht verfuegbar.'; } + if ($user && $action === 'clear_audit_logs' && $user['role'] === 'admin') { + if ($pdo) { + $pdo->exec('TRUNCATE TABLE audit_logs'); + addAuditLog($pdo, (int)$user['id'], 'Audit-Log geleert.'); + $notice = 'Logeintraege wurden geloescht.'; + } else { + $error = 'Logeintraege koennen ohne Datenbank nicht geloescht werden.'; + } + } + if ($user && $action === 'import_sql_dump' && $user['role'] === 'admin') { if (!$pdo) { $error = 'SQL-Wiederherstellung ist ohne Datenbank nicht verfuegbar.'; @@ -928,7 +958,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($user && $action === 'logout') { addAuditLog($pdo, (int)$user['id'], 'Abmeldung erfolgt.'); session_destroy(); - header('Location: /?page=login'); + header('Location: ' . appPath('?page=login')); exit; } } diff --git a/httpdocs/app/views.php b/httpdocs/app/views.php index 83c76a5..d66e940 100644 --- a/httpdocs/app/views.php +++ b/httpdocs/app/views.php @@ -477,7 +477,7 @@ function renderLoginPage(): void ?>
@@ -519,7 +519,7 @@ function renderResetPasswordPage(): void
- +
@@ -565,12 +565,12 @@ function renderAppShell(string $page): void
-

Logansicht


  • :
  • Keine Logeinträge vorhanden.
1): ?>
Zurück
Seite von , insgesamt Einträge
Weiter
+

Logansicht


  • :
  • Keine Logeinträge vorhanden.
1): ?>
Zurück
Seite von , insgesamt Einträge
Weiter
diff --git a/httpdocs/index.php b/httpdocs/index.php index 2b9ba27..ccaa27a 100644 --- a/httpdocs/index.php +++ b/httpdocs/index.php @@ -11,18 +11,18 @@ if (!function_exists('renderHeader') || !function_exists('renderAppShell')) { } if ($pdo && !isInstalled($pdo)) { - header('Location: /install.php'); + header('Location: ' . appPath('install.php')); exit; } -$page = $_GET['page'] ?? 'dashboard'; +$page = $_GET['page'] ?? 'home'; if (!currentUser() && !in_array($page, ['login', 'reset_password'], true)) { $page = 'login'; } $current = currentUser(); if ($current && ($current['role'] ?? '') === 'member' && in_array($page, ['members', 'admin', 'administration'], true)) { - $page = 'dashboard'; + $page = 'home'; } renderHeader(pageTitle($page)); diff --git a/httpdocs/install.php b/httpdocs/install.php index b4cf84b..d5be7d8 100644 --- a/httpdocs/install.php +++ b/httpdocs/install.php @@ -5,7 +5,7 @@ require __DIR__ . '/app/bootstrap.php'; require __DIR__ . '/app/views.php'; if ($pdo && isInstalled($pdo)) { - header('Location: /'); + header('Location: ' . appPath('')); exit; } @@ -31,7 +31,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'setup trim((string)$_POST['email']), password_hash((string)$_POST['password'], PASSWORD_DEFAULT), ]); - header('Location: /?page=login'); + header('Location: ' . appPath('?page=login')); exit; } catch (Throwable $e) { $installError = $e->getMessage();