develop #28
@ -100,4 +100,215 @@ class UserManagementController
|
||||
'activeMenu' => 'users',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt das Formular zum Anlegen eines neuen Benutzers (Platzhalter).
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function create(): array
|
||||
{
|
||||
// CSRF token sicherstellen
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));
|
||||
}
|
||||
|
||||
$viewPath = __DIR__ . '/../../public/views/users_create.php';
|
||||
|
||||
return [
|
||||
'view' => $viewPath,
|
||||
'data' => [
|
||||
'loginPage' => false,
|
||||
'csrf_token' => $_SESSION['csrf_token'],
|
||||
],
|
||||
'pageTitle' => 'Benutzer hinzufügen',
|
||||
'activeMenu' => 'users',
|
||||
'activeSubMenu' => 'create',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet das Absenden des 'Benutzer hinzufügen'-Formulars (Platzhalter,
|
||||
* führt keine LDAP-Änderung aus, validiert aber Eingaben).
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function createSubmit(): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
// CSRF prüfen
|
||||
$token = $_POST['csrf_token'] ?? '';
|
||||
if (empty($token) || !isset($_SESSION['csrf_token']) || hash_equals($_SESSION['csrf_token'], $token) === false) {
|
||||
$errors[] = 'Ungültiger CSRF-Token.';
|
||||
}
|
||||
|
||||
$username = trim((string)($_POST['username'] ?? ''));
|
||||
$firstname = trim((string)($_POST['givenName'] ?? ''));
|
||||
$lastname = trim((string)($_POST['sn'] ?? ''));
|
||||
$email = trim((string)($_POST['mail'] ?? ''));
|
||||
|
||||
if ($username === '') {
|
||||
$errors[] = 'Benutzername wird benötigt.';
|
||||
}
|
||||
if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
|
||||
$errors[] = 'E-Mail-Adresse ist ungültig.';
|
||||
}
|
||||
|
||||
// Für jetzt nur eine Erfolgsmeldung (keine AD-Operation)
|
||||
$viewPath = __DIR__ . '/../../public/views/users_create.php';
|
||||
|
||||
$data = [
|
||||
'loginPage' => false,
|
||||
'csrf_token' => $_SESSION['csrf_token'],
|
||||
];
|
||||
|
||||
if (!empty($errors)) {
|
||||
$data['errors'] = $errors;
|
||||
$data['form'] = [
|
||||
'username' => $username,
|
||||
'givenName' => $firstname,
|
||||
'sn' => $lastname,
|
||||
'mail' => $email,
|
||||
];
|
||||
|
||||
return [
|
||||
'view' => $viewPath,
|
||||
'data' => $data,
|
||||
'pageTitle' => 'Benutzer hinzufügen',
|
||||
'activeMenu' => 'users',
|
||||
'activeSubMenu' => 'create',
|
||||
];
|
||||
}
|
||||
|
||||
$data['success'] = 'Benutzer-Formular erfolgreich validiert (Platzhalter, wurde nicht angelegt).';
|
||||
$data['form'] = ['username' => $username];
|
||||
|
||||
return [
|
||||
'view' => $viewPath,
|
||||
'data' => $data,
|
||||
'pageTitle' => 'Benutzer hinzufügen',
|
||||
'activeMenu' => 'users',
|
||||
'activeSubMenu' => 'create',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt das CSV-Import-Formular (Platzhalter).
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function import(): array
|
||||
{
|
||||
// CSRF token sicherstellen
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));
|
||||
}
|
||||
|
||||
$viewPath = __DIR__ . '/../../public/views/users_import.php';
|
||||
|
||||
return [
|
||||
'view' => $viewPath,
|
||||
'data' => [
|
||||
'loginPage' => false,
|
||||
'csrf_token' => $_SESSION['csrf_token'],
|
||||
],
|
||||
'pageTitle' => 'Benutzer importieren (CSV)',
|
||||
'activeMenu' => 'users',
|
||||
'activeSubMenu' => 'import',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verarbeitet CSV-Upload und zeigt eine Vorschau der ersten Zeilen (Platzhalter).
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function importSubmit(): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
// CSRF prüfen
|
||||
$token = $_POST['csrf_token'] ?? '';
|
||||
if (empty($token) || !isset($_SESSION['csrf_token']) || hash_equals($_SESSION['csrf_token'], $token) === false) {
|
||||
$errors[] = 'Ungültiger CSRF-Token.';
|
||||
}
|
||||
|
||||
if (!isset($_FILES['csv_file']) || $_FILES['csv_file']['error'] !== UPLOAD_ERR_OK) {
|
||||
$errors[] = 'Bitte eine gültige CSV-Datei hochladen.';
|
||||
}
|
||||
|
||||
$preview = [];
|
||||
if (empty($errors)) {
|
||||
$tmp = $_FILES['csv_file']['tmp_name'];
|
||||
if (($handle = fopen($tmp, 'r')) !== false) {
|
||||
$row = 0;
|
||||
while (($data = fgetcsv($handle, 0, ',')) !== false && $row < 50) {
|
||||
$preview[] = $data;
|
||||
$row++;
|
||||
}
|
||||
fclose($handle);
|
||||
} else {
|
||||
$errors[] = 'Die hochgeladene Datei konnte nicht gelesen werden.';
|
||||
}
|
||||
}
|
||||
|
||||
$viewPath = __DIR__ . '/../../public/views/users_import.php';
|
||||
|
||||
$data = [
|
||||
'loginPage' => false,
|
||||
'csrf_token' => $_SESSION['csrf_token'],
|
||||
];
|
||||
|
||||
if (!empty($errors)) {
|
||||
$data['errors'] = $errors;
|
||||
} else {
|
||||
$data['preview'] = $preview;
|
||||
$data['success'] = 'CSV-Datei erfolgreich hochgeladen. Vorschau der ersten Zeilen:';
|
||||
}
|
||||
|
||||
return [
|
||||
'view' => $viewPath,
|
||||
'data' => $data,
|
||||
'pageTitle' => 'Benutzer importieren (CSV)',
|
||||
'activeMenu' => 'users',
|
||||
'activeSubMenu' => 'import',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Benutzersuche (Platzhalter).
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function search(): array
|
||||
{
|
||||
$query = trim((string)($_GET['q'] ?? ''));
|
||||
|
||||
$users = [];
|
||||
if ($query !== '') {
|
||||
try {
|
||||
$allUsers = $this->directoryService->getUsers();
|
||||
foreach ($allUsers as $u) {
|
||||
$hay = strtolower($u['samaccountname'] . ' ' . $u['displayname'] . ' ' . $u['mail']);
|
||||
if (strpos($hay, strtolower($query)) !== false) {
|
||||
$users[] = $u;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->logException('Fehler bei Benutzersuche.', $e, ['query' => $query]);
|
||||
}
|
||||
}
|
||||
|
||||
$viewPath = __DIR__ . '/../../public/views/users_search.php';
|
||||
|
||||
return [
|
||||
'view' => $viewPath,
|
||||
'data' => [
|
||||
'loginPage' => false,
|
||||
'query' => $query,
|
||||
'results' => $users,
|
||||
],
|
||||
'pageTitle' => 'Benutzer suchen',
|
||||
'activeMenu' => 'users',
|
||||
'activeSubMenu' => 'search',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,6 +240,44 @@ switch ($route) {
|
||||
handleResult($result);
|
||||
break;
|
||||
|
||||
case 'users.create':
|
||||
requireLogin($config);
|
||||
$result = $userManagementController->create();
|
||||
handleResult($result);
|
||||
break;
|
||||
|
||||
case 'users.create.submit':
|
||||
requireLogin($config);
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: index.php?route=users.create');
|
||||
exit;
|
||||
}
|
||||
$result = $userManagementController->createSubmit();
|
||||
handleResult($result);
|
||||
break;
|
||||
|
||||
case 'users.import':
|
||||
requireLogin($config);
|
||||
$result = $userManagementController->import();
|
||||
handleResult($result);
|
||||
break;
|
||||
|
||||
case 'users.import.submit':
|
||||
requireLogin($config);
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
header('Location: index.php?route=users.import');
|
||||
exit;
|
||||
}
|
||||
$result = $userManagementController->importSubmit();
|
||||
handleResult($result);
|
||||
break;
|
||||
|
||||
case 'users.search':
|
||||
requireLogin($config);
|
||||
$result = $userManagementController->search();
|
||||
handleResult($result);
|
||||
break;
|
||||
|
||||
default:
|
||||
http_response_code(404);
|
||||
echo 'Route nicht gefunden.';
|
||||
|
||||
@ -49,6 +49,23 @@
|
||||
<span>Benutzer & Gruppen</span></a>
|
||||
</li>
|
||||
|
||||
<!-- User actions (create/import/search) -->
|
||||
<li class="nav-item<?= (isset($activeSubMenu) && $activeSubMenu === 'create') ? ' active' : '' ?>">
|
||||
<a class="nav-link pl-4" href="../../index.php?route=users.create">
|
||||
<i class="fas fa-fw fa-user-plus"></i>
|
||||
<span>Benutzer hinzufügen</span></a>
|
||||
</li>
|
||||
<li class="nav-item<?= (isset($activeSubMenu) && $activeSubMenu === 'import') ? ' active' : '' ?>">
|
||||
<a class="nav-link pl-4" href="../../index.php?route=users.import">
|
||||
<i class="fas fa-fw fa-file-csv"></i>
|
||||
<span>Benutzer importieren (CSV)</span></a>
|
||||
</li>
|
||||
<li class="nav-item<?= (isset($activeSubMenu) && $activeSubMenu === 'search') ? ' active' : '' ?>">
|
||||
<a class="nav-link pl-4" href="../../index.php?route=users.search">
|
||||
<i class="fas fa-fw fa-search"></i>
|
||||
<span>Benutzer suchen</span></a>
|
||||
</li>
|
||||
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider d-none d-md-block">
|
||||
|
||||
|
||||
@ -25,6 +25,11 @@ declare(strict_types=1);
|
||||
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<h1 class="h3 mb-0 text-gray-800">Benutzer & Gruppen</h1>
|
||||
<div>
|
||||
<a href="index.php?route=users.create" class="btn btn-sm btn-primary mr-2"><i class="fas fa-user-plus"></i> Benutzer hinzufügen</a>
|
||||
<a href="index.php?route=users.import" class="btn btn-sm btn-success mr-2"><i class="fas fa-file-csv"></i> CSV importieren</a>
|
||||
<a href="index.php?route=users.search" class="btn btn-sm btn-info"><i class="fas fa-search"></i> Benutzer suchen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($error !== null): ?>
|
||||
|
||||
52
public/views/users_create.php
Normal file
52
public/views/users_create.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Platzhalter-View: Benutzer hinzufügen
|
||||
*/
|
||||
?>
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Benutzer hinzufügen</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (!empty($errors) && is_array($errors)): ?>
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<?php foreach ($errors as $e): ?>
|
||||
<li><?= htmlspecialchars($e, ENT_QUOTES, 'UTF-8') ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?= htmlspecialchars($success, ENT_QUOTES, 'UTF-8') ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" action="index.php?route=users.create.submit" class="user">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf_token ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="username">Benutzername</label>
|
||||
<input id="username" name="username" class="form-control" value="<?= htmlspecialchars($form['username'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="givenName">Vorname</label>
|
||||
<input id="givenName" name="givenName" class="form-control" value="<?= htmlspecialchars($form['givenName'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="sn">Nachname</label>
|
||||
<input id="sn" name="sn" class="form-control" value="<?= htmlspecialchars($form['sn'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="mail">E-Mail</label>
|
||||
<input id="mail" name="mail" class="form-control" value="<?= htmlspecialchars($form['mail'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Validieren (Platzhalter)</button>
|
||||
<a href="index.php?route=users" class="btn btn-secondary">Zurück zur Liste</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
55
public/views/users_import.php
Normal file
55
public/views/users_import.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Platzhalter-View: Benutzer importieren (CSV)
|
||||
*/
|
||||
?>
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Benutzer importieren (CSV)</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (!empty($errors) && is_array($errors)): ?>
|
||||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<?php foreach ($errors as $e): ?>
|
||||
<li><?= htmlspecialchars($e, ENT_QUOTES, 'UTF-8') ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?= htmlspecialchars($success, ENT_QUOTES, 'UTF-8') ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" action="index.php?route=users.import.submit" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf_token ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||||
<div class="form-group">
|
||||
<label for="csv_file">CSV-Datei</label>
|
||||
<input type="file" id="csv_file" name="csv_file" accept="text/csv" class="form-control">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Upload & Vorschau</button>
|
||||
<a href="index.php?route=users" class="btn btn-secondary">Zurück zur Liste</a>
|
||||
</form>
|
||||
|
||||
<?php if (!empty($preview) && is_array($preview)): ?>
|
||||
<h6 class="mt-4">Vorschau (erste Zeilen)</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<tbody>
|
||||
<?php foreach ($preview as $row): ?>
|
||||
<tr>
|
||||
<?php foreach ($row as $col): ?>
|
||||
<td><?= htmlspecialchars((string)$col, ENT_QUOTES, 'UTF-8') ?></td>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
48
public/views/users_search.php
Normal file
48
public/views/users_search.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Platzhalter-View: Benutzer suchen
|
||||
*/
|
||||
?>
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Benutzer suchen</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="get" action="index.php">
|
||||
<input type="hidden" name="route" value="users.search">
|
||||
<div class="form-group">
|
||||
<label for="q">Suche</label>
|
||||
<input id="q" name="q" class="form-control" value="<?= htmlspecialchars($query ?? '', ENT_QUOTES, 'UTF-8') ?>" placeholder="Namen, Benutzername oder E-Mail">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Suchen</button>
|
||||
<a href="index.php?route=users" class="btn btn-secondary">Zurück zur Liste</a>
|
||||
</form>
|
||||
|
||||
<?php if (!empty($query)): ?>
|
||||
<h6 class="mt-4">Ergebnisse für "<?= htmlspecialchars($query, ENT_QUOTES, 'UTF-8') ?>"</h6>
|
||||
<?php if (!empty($results) && is_array($results)): ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr><th>Benutzername</th><th>Name</th><th>E-Mail</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($results as $r): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($r['samaccountname'] ?? '', ENT_QUOTES, 'UTF-8') ?></td>
|
||||
<td><?= htmlspecialchars($r['displayname'] ?? '', ENT_QUOTES, 'UTF-8') ?></td>
|
||||
<td><?= htmlspecialchars($r['mail'] ?? '', ENT_QUOTES, 'UTF-8') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info mt-3">Keine Treffer gefunden.</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Reference in New Issue
Block a user