PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ] ); $currentUserId = (int)$_SESSION['user_id']; $loggedIn = true; $errors = []; $successMessage = ''; $pageTitle = 'Benutzerverwaltung'; $headerIntroPre = 'Administration'; $headerIntroTitle = 'Benutzerkonten verwalten'; $headerIntroSub = 'Konten freischalten, deaktivieren und Rollen verwalten'; function h(?string $value): string { return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8'); } function redirectToAdminUsers(): void { header('Location: admin_users.php'); exit; } function isPrivilegedRole(?string $role): bool { return isAdminLikeRole($role); } function ensureUserPagePermissionsTable(PDO $pdo): void { $pdo->exec(" CREATE TABLE IF NOT EXISTS `app_user_page_permissions` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `user_id` bigint(20) unsigned NOT NULL, `page_key` varchar(100) NOT NULL, `created_at` datetime NOT NULL DEFAULT current_timestamp(), `updated_at` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), PRIMARY KEY (`id`), UNIQUE KEY `uq_app_user_page_permissions_user_page` (`user_id`, `page_key`), KEY `idx_app_user_page_permissions_page_key` (`page_key`), CONSTRAINT `fk_app_user_page_permissions_user_id` FOREIGN KEY (`user_id`) REFERENCES `app_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci "); } function sendActivationNotification(string $username, string $email, ?string $displayName): void { $subject = 'Dein SkyView-Konto wurde freigeschaltet'; $recipientName = $displayName !== null && $displayName !== '' ? $displayName : $username; $messageLines = [ 'Hallo ' . $recipientName . ',', '', 'dein Benutzerkonto bei SkyView wurde soeben freigeschaltet.', 'Du kannst dich ab sofort mit deinen Zugangsdaten anmelden.', '', 'Benutzername: ' . $username, '', 'Zum Einstieg sind bereits erste Standarddaten für dich hinterlegt:', 'als Standort die Sternwarte Sonneberg und als Satellit die ISS.', '', 'Nach der Anmeldung kannst du in Ruhe über das Menu und Favoriten', 'deinen eigenen Standort und deine eigenen Satelliten anlegen', 'und die gewünschten Einträge als Favoriten markieren.', '', 'Wenn du Telegram-Benachrichtigungen nutzen möchtest,', 'verbinde dein Telegram-Konto bitte in den Einstellungen.', 'Danach kannst du auswählen, welche Nachrichten', 'du per Telegram erhalten möchtest.', '', 'SkyView befindet sich derzeit noch in der Alpha-Phase.', 'Hinweise zu Fehlern, Auffälligkeiten oder Ideen sind jederzeit willkommen.', '', 'Viele Grüße', 'Astronomiemuseum der Sternwarte Sonneberg', ]; $headers = [ 'MIME-Version: 1.0', 'Content-Type: text/plain; charset=UTF-8', 'From: noreply@astronomiemuseum.de', 'Reply-To: tm@astronomiemuseum.de', ]; try { mail( $email, $subject, implode(PHP_EOL, $messageLines), implode("\r\n", $headers) ); } catch (Throwable $e) { error_log('Activation notification mail failed: ' . $e->getMessage()); } } if (empty($_SESSION['admin_users_csrf'])) { $_SESSION['admin_users_csrf'] = bin2hex(random_bytes(16)); } $stmtCurrentUser = $pdo->prepare(" SELECT `id`, `username`, `display_name`, `role`, `is_active` FROM `app_users` WHERE `id` = :id LIMIT 1 "); $stmtCurrentUser->execute([':id' => $currentUserId]); $currentUser = $stmtCurrentUser->fetch(); if ( !$currentUser || !isAdminLikeRole((string) $currentUser['role']) || (int)$currentUser['is_active'] !== 1 ) { $_SESSION = []; session_destroy(); header('Location: login.php'); exit; } $currentUserIsMaster = isMasterRole((string) ($currentUser['role'] ?? '')); $manageablePages = manageablePublicPages(); if ($currentUserIsMaster) { ensureUserPagePermissionsTable($pdo); } if (isset($_SESSION['admin_users_flash_success'])) { $successMessage = (string)$_SESSION['admin_users_flash_success']; unset($_SESSION['admin_users_flash_success']); } if (isset($_SESSION['admin_users_flash_errors']) && is_array($_SESSION['admin_users_flash_errors'])) { $errors = array_values($_SESSION['admin_users_flash_errors']); unset($_SESSION['admin_users_flash_errors']); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; $targetUserId = (int)($_POST['user_id'] ?? 0); $csrfToken = (string)($_POST['csrf_token'] ?? ''); if (!hash_equals($_SESSION['admin_users_csrf'], $csrfToken)) { $errors[] = 'Die Sitzung ist abgelaufen. Bitte die Seite neu laden.'; } $stmtTargetUser = $pdo->prepare(" SELECT `id`, `username`, `email`, `display_name`, `role`, `is_active` FROM `app_users` WHERE `id` = :id LIMIT 1 "); $targetUser = null; if ($targetUserId > 0) { $stmtTargetUser->execute([':id' => $targetUserId]); $targetUser = $stmtTargetUser->fetch(); } if ($action === 'update_page_permissions' && !$currentUserIsMaster) { $errors[] = 'Nur ein Master-Benutzer darf Seitenfreigaben verwalten.'; } if (!$targetUser) { $errors[] = 'Das ausgewählte Benutzerkonto wurde nicht gefunden.'; } if ($targetUser && $targetUserId === $currentUserId && in_array($action, ['deactivate_user', 'change_role', 'delete_user'], true)) { $errors[] = 'Das eigene Administrationskonto kann hier nicht deaktiviert, gelöscht oder umgestellt werden.'; } $currentUserIsMaster = isMasterRole((string) ($currentUser['role'] ?? '')); $targetUserIsMaster = $targetUser ? isMasterRole((string) ($targetUser['role'] ?? '')) : false; $requestedRole = (string) ($_POST['role'] ?? 'user'); if (empty($errors) && $targetUser) { $stmtActiveAdminCount = $pdo->query(" SELECT COUNT(*) FROM `app_users` WHERE `role` IN ('admin', 'master') AND `is_active` = 1 "); $activeAdminCount = (int)$stmtActiveAdminCount->fetchColumn(); $stmtMasterCount = $pdo->query(" SELECT COUNT(*) FROM `app_users` WHERE `role` = 'master' "); $masterCount = (int)$stmtMasterCount->fetchColumn(); if ( !$currentUserIsMaster && $targetUserIsMaster ) { $errors[] = 'Nur ein Master-Benutzer darf die Rolle master vergeben oder ändern.'; } if ( !$currentUserIsMaster && $requestedRole === 'master' && $masterCount > 0 ) { $errors[] = 'Nur ein Master-Benutzer darf die Rolle master vergeben oder ändern.'; } if ( $action === 'deactivate_user' && isPrivilegedRole((string) $targetUser['role']) && (int)$targetUser['is_active'] === 1 && $activeAdminCount <= 1 ) { $errors[] = 'Der letzte aktive privilegierte Benutzer kann nicht deaktiviert werden.'; } if ( $action === 'change_role' && isPrivilegedRole((string) $targetUser['role']) && !isPrivilegedRole($requestedRole) && (int)$targetUser['is_active'] === 1 && $activeAdminCount <= 1 ) { $errors[] = 'Der letzte aktive privilegierte Benutzer kann nicht zur Benutzerrolle herabgestuft werden.'; } if ( $action === 'delete_user' && isPrivilegedRole((string) $targetUser['role']) && (int)$targetUser['is_active'] === 1 && $activeAdminCount <= 1 ) { $errors[] = 'Der letzte aktive privilegierte Benutzer kann nicht gelöscht werden.'; } } if (empty($errors) && $targetUser) { if ($action === 'activate_user') { $notifyUser = (int)($_POST['notify_user'] ?? 0) === 1; $stmtUpdate = $pdo->prepare(" UPDATE `app_users` SET `is_active` = 1, `updated_at` = NOW() WHERE `id` = :id "); $stmtUpdate->execute([':id' => $targetUserId]); if ($notifyUser) { sendActivationNotification( $targetUser['username'], $targetUser['email'], $targetUser['display_name'] ); $_SESSION['admin_users_flash_success'] = 'Benutzerkonto wurde freigeschaltet und der Benutzer wurde benachrichtigt.'; } else { $_SESSION['admin_users_flash_success'] = 'Benutzerkonto wurde freigeschaltet.'; } redirectToAdminUsers(); } if ($action === 'deactivate_user') { $stmtUpdate = $pdo->prepare(" UPDATE `app_users` SET `is_active` = 0, `updated_at` = NOW() WHERE `id` = :id "); $stmtUpdate->execute([':id' => $targetUserId]); $_SESSION['admin_users_flash_success'] = 'Benutzerkonto wurde deaktiviert.'; redirectToAdminUsers(); } if ($action === 'change_role') { $newRole = $requestedRole; if (!in_array($newRole, ['user', 'admin', 'master'], true)) { $errors[] = 'Die gewählte Rolle ist ungültig.'; } else { $stmtUpdate = $pdo->prepare(" UPDATE `app_users` SET `role` = :role, `updated_at` = NOW() WHERE `id` = :id "); $stmtUpdate->execute([ ':role' => $newRole, ':id' => $targetUserId, ]); $_SESSION['admin_users_flash_success'] = 'Die Benutzerrolle wurde aktualisiert.'; redirectToAdminUsers(); } } if ($action === 'delete_user') { $stmtDelete = $pdo->prepare(" DELETE FROM `app_users` WHERE `id` = :id "); $stmtDelete->execute([ ':id' => $targetUserId, ]); $_SESSION['admin_users_flash_success'] = 'Benutzerkonto wurde gelöscht. Zugehörige Standorte und Satelliten wurden automatisch entfernt.'; redirectToAdminUsers(); } if ($action === 'update_page_permissions' && $currentUserIsMaster) { $submittedPages = array_values(array_unique(array_filter(array_map( static fn ($value): string => trim((string) $value), is_array($_POST['page_keys'] ?? null) ? $_POST['page_keys'] : [] ), static fn (string $value): bool => $value !== ''))); $submittedPages = array_values(array_intersect($submittedPages, array_keys($manageablePages))); $pdo->beginTransaction(); try { $stmtDeletePermissions = $pdo->prepare(" DELETE FROM `app_user_page_permissions` WHERE `user_id` = :user_id "); $stmtDeletePermissions->execute([ ':user_id' => $targetUserId, ]); if ($submittedPages !== []) { $stmtInsertPermission = $pdo->prepare(" INSERT INTO `app_user_page_permissions` ( `user_id`, `page_key`, `created_at`, `updated_at` ) VALUES ( :user_id, :page_key, NOW(), NOW() ) "); foreach ($submittedPages as $pageKey) { $stmtInsertPermission->execute([ ':user_id' => $targetUserId, ':page_key' => $pageKey, ]); } } $pdo->commit(); } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } throw $e; } $_SESSION['admin_users_flash_success'] = 'Die Seitenfreigaben wurden aktualisiert.'; redirectToAdminUsers(); } } if (!empty($errors)) { $_SESSION['admin_users_flash_errors'] = $errors; redirectToAdminUsers(); } } $stats = [ 'total' => 0, 'active' => 0, 'pending' => 0, 'admins' => 0, 'masters' => 0, ]; $stmtStats = $pdo->query(" SELECT COUNT(*) AS total_users, SUM(CASE WHEN `is_active` = 1 THEN 1 ELSE 0 END) AS active_users, SUM(CASE WHEN `is_active` = 0 THEN 1 ELSE 0 END) AS pending_users, SUM(CASE WHEN `role` = 'admin' THEN 1 ELSE 0 END) AS admin_users, SUM(CASE WHEN `role` = 'master' THEN 1 ELSE 0 END) AS master_users FROM `app_users` "); $statsRow = $stmtStats->fetch(); if ($statsRow) { $stats['total'] = (int)$statsRow['total_users']; $stats['active'] = (int)$statsRow['active_users']; $stats['pending'] = (int)$statsRow['pending_users']; $stats['admins'] = (int)$statsRow['admin_users']; $stats['masters'] = (int)$statsRow['master_users']; } $stmtUsers = $pdo->query(" SELECT `id`, `username`, `email`, `display_name`, `role`, `is_active`, `last_login_at`, `created_at`, `updated_at` FROM `app_users` ORDER BY `is_active` ASC, `role` DESC, `created_at` DESC, `username` ASC "); $users = $stmtUsers->fetchAll(); $pagePermissionsByUser = []; if ($currentUserIsMaster) { $stmtPagePermissions = $pdo->query(" SELECT `user_id`, `page_key` FROM `app_user_page_permissions` ORDER BY `user_id` ASC, `page_key` ASC "); foreach ($stmtPagePermissions as $permissionRow) { $permissionUserId = (int) ($permissionRow['user_id'] ?? 0); $permissionPageKey = (string) ($permissionRow['page_key'] ?? ''); if ($permissionUserId < 1 || $permissionPageKey === '') { continue; } if (!isset($pagePermissionsByUser[$permissionUserId])) { $pagePermissionsByUser[$permissionUserId] = []; } $pagePermissionsByUser[$permissionUserId][$permissionPageKey] = true; } } ?>
Hier kannst du Benutzerkonten freischalten, deaktivieren, löschen und zwischen user, admin und master wechseln.
= h($successMessage) ?>
| Benutzer | Status | Rolle | Registriert | Letzter Login | Aktionen |
|---|---|---|---|---|---|
|
= h($userRow['display_name'] ?: $userRow['username']) ?>
= h($userRow['username']) ?>
= h($userRow['email']) ?>
Dieses Konto
|
= h($statusLabel) ?> | = h($userRow['role']) ?> | = h($userRow['created_at']) ?> | = h($userRow['last_login_at'] ?: 'Noch nie') ?> |
|
Nur Master-Benutzer dürfen hier festlegen, welche Seiten normale Nutzer im Menü sehen und direkt aufrufen dürfen.
| Benutzer | $pageLabel): ?>= h($pageLabel) ?> | Speichern |
|---|---|---|
|
= h($userRow['display_name'] ?: $userRow['username']) ?> = h($userRow['username']) ?> (= h($userRow['role']) ?>) |
$pageLabel): ?>
= $isPrivilegedUser ? 'disabled' : '' ?> > | Vollzugriff über Rolle |