811 lines
31 KiB
PHP
811 lines
31 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
ini_set('display_errors', '1');
|
|
error_reporting(E_ALL);
|
|
session_start();
|
|
|
|
if (!isset($_SESSION['user_id'])) {
|
|
header('Location: login.php');
|
|
exit;
|
|
}
|
|
|
|
require_once __DIR__ . '/auth_helpers.php';
|
|
|
|
$config = require __DIR__ . '/../config/database.php';
|
|
|
|
$dsn = sprintf(
|
|
'mysql:host=%s;dbname=%s;charset=%s',
|
|
$config['host'],
|
|
$config['dbname'],
|
|
$config['charset'] ?? 'utf8mb4'
|
|
);
|
|
|
|
$pdo = new PDO(
|
|
$dsn,
|
|
$config['user'],
|
|
$config['pass'],
|
|
[
|
|
PDO::ATTR_ERRMODE => 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,
|
|
'',
|
|
'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;
|
|
}
|
|
}
|
|
?>
|
|
<?php require __DIR__ . '/header.php'; ?>
|
|
|
|
<style>
|
|
.admin-users-table.permissions-matrix {
|
|
width: auto;
|
|
min-width: max-content;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix thead th {
|
|
vertical-align: bottom;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix thead th.permissions-matrix-head {
|
|
width: 22px;
|
|
min-width: 22px;
|
|
padding: 0.2rem 0.02rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix thead th.permissions-matrix-head > span {
|
|
display: inline-flex;
|
|
align-items: flex-end;
|
|
justify-content: center;
|
|
min-height: 96px;
|
|
writing-mode: vertical-rl;
|
|
transform: rotate(180deg);
|
|
white-space: nowrap;
|
|
font-size: 0.56rem;
|
|
letter-spacing: 0;
|
|
line-height: 1.05;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix td {
|
|
min-width: 22px;
|
|
padding: 0.2rem 0.02rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix td input[type="checkbox"] {
|
|
margin: 0;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix td:first-child,
|
|
.admin-users-table.permissions-matrix th:first-child,
|
|
.admin-users-table.permissions-matrix td:last-child,
|
|
.admin-users-table.permissions-matrix th:last-child {
|
|
text-align: left;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix td:first-child,
|
|
.admin-users-table.permissions-matrix th:first-child {
|
|
min-width: 150px;
|
|
padding-right: 0.45rem;
|
|
}
|
|
|
|
.admin-users-table.permissions-matrix td:last-child,
|
|
.admin-users-table.permissions-matrix th:last-child {
|
|
min-width: 92px;
|
|
padding-left: 0.45rem;
|
|
white-space: nowrap;
|
|
}
|
|
</style>
|
|
|
|
<div class="admin-users-layout">
|
|
<section class="card admin-users-summary-card">
|
|
<h2>Übersicht</h2>
|
|
<p class="hint">Hier kannst du Benutzerkonten freischalten, deaktivieren, löschen und zwischen <strong>user</strong>, <strong>admin</strong> und <strong>master</strong> wechseln.</p>
|
|
|
|
<?php if ($successMessage !== ''): ?>
|
|
<p class="msg-success"><?= h($successMessage) ?></p>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($errors)): ?>
|
|
<ul class="msg-error">
|
|
<?php foreach ($errors as $error): ?>
|
|
<li><?= h((string)$error) ?></li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php endif; ?>
|
|
|
|
<div class="admin-stats-grid">
|
|
<div class="admin-stat-box">
|
|
<span class="admin-stat-label">Gesamt</span>
|
|
<strong><?= $stats['total'] ?></strong>
|
|
</div>
|
|
<div class="admin-stat-box">
|
|
<span class="admin-stat-label">Aktiv</span>
|
|
<strong><?= $stats['active'] ?></strong>
|
|
</div>
|
|
<div class="admin-stat-box admin-stat-box-warning">
|
|
<span class="admin-stat-label">Warten auf Freischaltung</span>
|
|
<strong><?= $stats['pending'] ?></strong>
|
|
</div>
|
|
<div class="admin-stat-box">
|
|
<span class="admin-stat-label">Admins</span>
|
|
<strong><?= $stats['admins'] ?></strong>
|
|
</div>
|
|
<div class="admin-stat-box">
|
|
<span class="admin-stat-label">Master</span>
|
|
<strong><?= $stats['masters'] ?></strong>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="card admin-users-table-card">
|
|
<h2>Benutzerkonten</h2>
|
|
<div class="admin-users-table-wrap">
|
|
<table class="data-table admin-users-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Benutzer</th>
|
|
<th>Status</th>
|
|
<th>Rolle</th>
|
|
<th>Registriert</th>
|
|
<th>Letzter Login</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($users as $userRow): ?>
|
|
<?php
|
|
$isSelf = (int)$userRow['id'] === $currentUserId;
|
|
$isActive = (int)$userRow['is_active'] === 1;
|
|
$statusLabel = $isActive ? 'Aktiv' : 'Wartet auf Freischaltung';
|
|
?>
|
|
<tr>
|
|
<td>
|
|
<div class="admin-user-main">
|
|
<strong><?= h($userRow['display_name'] ?: $userRow['username']) ?></strong>
|
|
<span><?= h($userRow['username']) ?></span>
|
|
<span><?= h($userRow['email']) ?></span>
|
|
<?php if ($isSelf): ?>
|
|
<span class="admin-user-self">Dieses Konto</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="status-badge <?= $isActive ? 'status-badge-active' : 'status-badge-pending' ?>">
|
|
<?= h($statusLabel) ?>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<span class="role-badge <?= in_array($userRow['role'], ['admin', 'master'], true) ? 'role-badge-admin' : 'role-badge-user' ?>">
|
|
<?= h($userRow['role']) ?>
|
|
</span>
|
|
</td>
|
|
<td><?= h($userRow['created_at']) ?></td>
|
|
<td><?= h($userRow['last_login_at'] ?: 'Noch nie') ?></td>
|
|
<td>
|
|
<div class="admin-actions">
|
|
<form method="post" class="admin-inline-form js-activate-user-form" data-username="<?= h($userRow['username']) ?>">
|
|
<input type="hidden" name="csrf_token" value="<?= h($_SESSION['admin_users_csrf']) ?>">
|
|
<input type="hidden" name="user_id" value="<?= (int)$userRow['id'] ?>">
|
|
<input type="hidden" name="notify_user" value="0">
|
|
<?php if ($isActive): ?>
|
|
<input type="hidden" name="action" value="deactivate_user">
|
|
<button type="submit" class="btn btn-danger btn-sm"<?= $isSelf ? ' disabled' : '' ?>>Deaktivieren</button>
|
|
<?php else: ?>
|
|
<input type="hidden" name="action" value="activate_user">
|
|
<button type="submit" class="btn btn-primary btn-sm">Freischalten</button>
|
|
<?php endif; ?>
|
|
</form>
|
|
|
|
<form method="post" class="admin-inline-form admin-role-form">
|
|
<input type="hidden" name="csrf_token" value="<?= h($_SESSION['admin_users_csrf']) ?>">
|
|
<input type="hidden" name="action" value="change_role">
|
|
<input type="hidden" name="user_id" value="<?= (int)$userRow['id'] ?>">
|
|
<select name="role"<?= $isSelf ? ' disabled' : '' ?>>
|
|
<option value="user"<?= $userRow['role'] === 'user' ? ' selected' : '' ?>>user</option>
|
|
<option value="admin"<?= $userRow['role'] === 'admin' ? ' selected' : '' ?>>admin</option>
|
|
<?php if ($currentUserIsMaster || $userRow['role'] === 'master'): ?>
|
|
<option value="master"<?= $userRow['role'] === 'master' ? ' selected' : '' ?>>master</option>
|
|
<?php endif; ?>
|
|
</select>
|
|
<button type="submit" class="btn btn-secondary btn-sm"<?= $isSelf ? ' disabled' : '' ?>>Rolle speichern</button>
|
|
</form>
|
|
|
|
<form method="post" class="admin-inline-form js-delete-user-form" data-username="<?= h($userRow['username']) ?>">
|
|
<input type="hidden" name="csrf_token" value="<?= h($_SESSION['admin_users_csrf']) ?>">
|
|
<input type="hidden" name="action" value="delete_user">
|
|
<input type="hidden" name="user_id" value="<?= (int)$userRow['id'] ?>">
|
|
<button type="submit" class="btn btn-danger btn-sm"<?= $isSelf ? ' disabled' : '' ?>>Benutzer löschen</button>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
|
|
<?php if ($currentUserIsMaster): ?>
|
|
<section class="card admin-users-table-card">
|
|
<h2>Seitenfreigaben</h2>
|
|
<p class="hint">Nur Master-Benutzer dürfen hier festlegen, welche Seiten normale Nutzer im Menü sehen und direkt aufrufen dürfen.</p>
|
|
<div class="admin-users-table-wrap">
|
|
<table class="data-table admin-users-table permissions-matrix">
|
|
<thead>
|
|
<tr>
|
|
<th>Benutzer</th>
|
|
<?php foreach ($manageablePages as $pageKey => $pageLabel): ?>
|
|
<th class="permissions-matrix-head"><span><?= h($pageLabel) ?></span></th>
|
|
<?php endforeach; ?>
|
|
<th>Speichern</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($users as $userRow): ?>
|
|
<?php
|
|
$permissionUserId = (int) $userRow['id'];
|
|
$userPermissions = $pagePermissionsByUser[$permissionUserId] ?? [];
|
|
$isPrivilegedUser = isPrivilegedRole((string) ($userRow['role'] ?? ''));
|
|
$permissionFormId = 'page-permissions-user-' . $permissionUserId;
|
|
?>
|
|
<tr>
|
|
<td>
|
|
<form id="<?= h($permissionFormId) ?>" method="post" action="">
|
|
<input type="hidden" name="csrf_token" value="<?= h($_SESSION['admin_users_csrf']) ?>">
|
|
<input type="hidden" name="action" value="update_page_permissions">
|
|
<input type="hidden" name="user_id" value="<?= $permissionUserId ?>">
|
|
</form>
|
|
<strong><?= h($userRow['display_name'] ?: $userRow['username']) ?></strong><br>
|
|
<small><?= h($userRow['username']) ?> (<?= h($userRow['role']) ?>)</small>
|
|
</td>
|
|
<?php foreach ($manageablePages as $pageKey => $pageLabel): ?>
|
|
<td>
|
|
<input
|
|
type="checkbox"
|
|
name="page_keys[]"
|
|
value="<?= h($pageKey) ?>"
|
|
form="<?= h($permissionFormId) ?>"
|
|
title="<?= h($pageLabel) ?>"
|
|
aria-label="<?= h($pageLabel) ?>"
|
|
<?= isset($userPermissions[$pageKey]) ? 'checked' : '' ?>
|
|
<?= $isPrivilegedUser ? 'disabled' : '' ?>
|
|
>
|
|
</td>
|
|
<?php endforeach; ?>
|
|
<td>
|
|
<?php if ($isPrivilegedUser): ?>
|
|
<span class="hint">Vollzugriff über Rolle</span>
|
|
<?php else: ?>
|
|
<button type="submit" class="btn btn-secondary btn-sm" form="<?= h($permissionFormId) ?>">Freigaben speichern</button>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<dialog class="admin-dialog" id="activateNotifyDialog">
|
|
<form method="dialog" class="admin-dialog-card">
|
|
<h3>Benutzer benachrichtigen?</h3>
|
|
<p id="activateNotifyDialogText">Soll der Benutzer benachrichtigt werden?</p>
|
|
<div class="admin-dialog-actions">
|
|
<button type="button" class="btn btn-secondary" data-notify-choice="no">Nein</button>
|
|
<button type="button" class="btn btn-primary" data-notify-choice="yes">Ja</button>
|
|
</div>
|
|
</form>
|
|
</dialog>
|
|
|
|
<dialog class="admin-dialog" id="deleteUserDialog">
|
|
<form method="dialog" class="admin-dialog-card">
|
|
<h3>Benutzer löschen?</h3>
|
|
<p id="deleteUserDialogText">Soll dieser Benutzer wirklich gelöscht werden?</p>
|
|
<div class="admin-dialog-actions">
|
|
<button type="button" class="btn btn-secondary" data-delete-choice="no">Abbrechen</button>
|
|
<button type="button" class="btn btn-danger" data-delete-choice="yes">Löschen</button>
|
|
</div>
|
|
</form>
|
|
</dialog>
|
|
|
|
<script>
|
|
(function () {
|
|
const dialog = document.getElementById('activateNotifyDialog');
|
|
const dialogText = document.getElementById('activateNotifyDialogText');
|
|
const activateForms = document.querySelectorAll('.js-activate-user-form');
|
|
const deleteDialog = document.getElementById('deleteUserDialog');
|
|
const deleteDialogText = document.getElementById('deleteUserDialogText');
|
|
const deleteForms = document.querySelectorAll('.js-delete-user-form');
|
|
|
|
if (!dialog || !dialogText || activateForms.length === 0 || typeof dialog.showModal !== 'function') {
|
|
return;
|
|
}
|
|
|
|
let pendingForm = null;
|
|
let pendingDeleteForm = null;
|
|
|
|
activateForms.forEach(function (form) {
|
|
const actionInput = form.querySelector('input[name="action"]');
|
|
if (!actionInput || actionInput.value !== 'activate_user') {
|
|
return;
|
|
}
|
|
|
|
form.addEventListener('submit', function (event) {
|
|
event.preventDefault();
|
|
pendingForm = form;
|
|
|
|
const username = form.getAttribute('data-username') || 'dieser Benutzer';
|
|
dialogText.textContent = 'Benutzer "' + username + '" benachrichtigen?';
|
|
dialog.showModal();
|
|
});
|
|
});
|
|
|
|
dialog.querySelectorAll('[data-notify-choice]').forEach(function (button) {
|
|
button.addEventListener('click', function () {
|
|
if (!pendingForm) {
|
|
dialog.close();
|
|
return;
|
|
}
|
|
|
|
const notifyInput = pendingForm.querySelector('input[name="notify_user"]');
|
|
if (notifyInput) {
|
|
notifyInput.value = button.getAttribute('data-notify-choice') === 'yes' ? '1' : '0';
|
|
}
|
|
|
|
dialog.close();
|
|
pendingForm.submit();
|
|
pendingForm = null;
|
|
});
|
|
});
|
|
|
|
dialog.addEventListener('cancel', function () {
|
|
pendingForm = null;
|
|
});
|
|
|
|
if (deleteDialog && deleteDialogText && deleteForms.length > 0 && typeof deleteDialog.showModal === 'function') {
|
|
deleteForms.forEach(function (form) {
|
|
form.addEventListener('submit', function (event) {
|
|
event.preventDefault();
|
|
pendingDeleteForm = form;
|
|
|
|
const username = form.getAttribute('data-username') || 'dieser Benutzer';
|
|
deleteDialogText.textContent = 'Benutzer "' + username + '" wirklich löschen? Standorte und Satelliten dieses Kontos werden ebenfalls entfernt.';
|
|
deleteDialog.showModal();
|
|
});
|
|
});
|
|
|
|
deleteDialog.querySelectorAll('[data-delete-choice]').forEach(function (button) {
|
|
button.addEventListener('click', function () {
|
|
if (!pendingDeleteForm) {
|
|
deleteDialog.close();
|
|
return;
|
|
}
|
|
|
|
if (button.getAttribute('data-delete-choice') === 'yes') {
|
|
deleteDialog.close();
|
|
pendingDeleteForm.submit();
|
|
pendingDeleteForm = null;
|
|
return;
|
|
}
|
|
|
|
deleteDialog.close();
|
|
pendingDeleteForm = null;
|
|
});
|
|
});
|
|
|
|
deleteDialog.addEventListener('cancel', function () {
|
|
pendingDeleteForm = null;
|
|
});
|
|
}
|
|
})();
|
|
</script>
|
|
|
|
<?php require __DIR__ . '/footer.php'; ?>
|