Admin-Accounts-Editor (CRUD inkl. 2FA-Mail) + Regel: Lehrer-Username = E-Mail (Maske + register), Schueler frei
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin API: Verwaltung der Super-Admin-Accounts (inkl. 2FA-Mailadresse)
|
||||
* POST /api/admin-accounts {action}
|
||||
* - list → alle Admins (ohne Passwort-Hash)
|
||||
* - create {username, email_2fa, password} → neuen Admin anlegen
|
||||
* - update {id, email_2fa?, password?} → 2FA-Mail und/oder Passwort ändern
|
||||
* - delete {id} → Admin löschen (nicht sich selbst, nicht den letzten)
|
||||
*
|
||||
* Auth: eingeloggter Super-Admin ($_SESSION['admin_id']). Nur Admins verwalten Admins.
|
||||
*/
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) session_start();
|
||||
|
||||
if (empty($_SESSION['admin_id'])) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['error' => 'Nicht eingeloggt']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$meId = (int)$_SESSION['admin_id'];
|
||||
$db = Database::get();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
Response::error('Nur POST erlaubt', 405);
|
||||
}
|
||||
|
||||
$body = json_decode(file_get_contents('php://input'), true) ?: [];
|
||||
$action = $body['action'] ?? '';
|
||||
|
||||
// === LISTE ===
|
||||
if ($action === 'list') {
|
||||
$rows = $db->fetchAll('SELECT id, username, email_2fa, created_at FROM admin_users ORDER BY id');
|
||||
foreach ($rows as &$r) {
|
||||
$r['id'] = (int)$r['id'];
|
||||
$r['is_self'] = ($r['id'] === $meId);
|
||||
}
|
||||
unset($r);
|
||||
Response::ok(['admins' => $rows]);
|
||||
}
|
||||
|
||||
// === ANLEGEN ===
|
||||
if ($action === 'create') {
|
||||
$username = trim($body['username'] ?? '');
|
||||
$email = trim($body['email_2fa'] ?? '');
|
||||
$password = (string)($body['password'] ?? '');
|
||||
|
||||
if ($username === '' || $email === '' || $password === '') {
|
||||
Response::error('Benutzername, 2FA-E-Mail und Passwort sind erforderlich.');
|
||||
}
|
||||
if (!preg_match('/^[A-Za-z0-9._\-]{3,64}$/', $username)) {
|
||||
Response::error('Benutzername: 3–64 Zeichen, nur Buchstaben, Ziffern, Punkt, Unterstrich, Bindestrich.');
|
||||
}
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
Response::error('Ungültige 2FA-E-Mail-Adresse.');
|
||||
}
|
||||
if (strlen($password) < 10) {
|
||||
Response::error('Passwort muss mindestens 10 Zeichen haben.');
|
||||
}
|
||||
if ($db->fetchOne('SELECT id FROM admin_users WHERE username = ?', [$username])) {
|
||||
Response::error('Dieser Benutzername ist bereits vergeben.');
|
||||
}
|
||||
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
$db->execute(
|
||||
'INSERT INTO admin_users (username, password, email_2fa) VALUES (?, ?, ?)',
|
||||
[$username, $hash, $email]
|
||||
);
|
||||
Response::ok(['message' => 'Admin-Account angelegt.']);
|
||||
}
|
||||
|
||||
// === AKTUALISIEREN (2FA-Mail und/oder Passwort) ===
|
||||
if ($action === 'update') {
|
||||
$id = (int)($body['id'] ?? 0);
|
||||
if (!$id) Response::error('ID fehlt.');
|
||||
if (!$db->fetchOne('SELECT id FROM admin_users WHERE id = ?', [$id])) {
|
||||
Response::error('Admin nicht gefunden.', 404);
|
||||
}
|
||||
|
||||
$didSomething = false;
|
||||
|
||||
if (array_key_exists('email_2fa', $body)) {
|
||||
$email = trim((string)$body['email_2fa']);
|
||||
if ($email === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
Response::error('Ungültige 2FA-E-Mail-Adresse.');
|
||||
}
|
||||
$db->execute('UPDATE admin_users SET email_2fa = ? WHERE id = ?', [$email, $id]);
|
||||
$didSomething = true;
|
||||
}
|
||||
|
||||
if (array_key_exists('password', $body) && (string)$body['password'] !== '') {
|
||||
$password = (string)$body['password'];
|
||||
if (strlen($password) < 10) {
|
||||
Response::error('Passwort muss mindestens 10 Zeichen haben.');
|
||||
}
|
||||
$db->execute(
|
||||
'UPDATE admin_users SET password = ? WHERE id = ?',
|
||||
[password_hash($password, PASSWORD_DEFAULT), $id]
|
||||
);
|
||||
$didSomething = true;
|
||||
}
|
||||
|
||||
if (!$didSomething) Response::error('Nichts zu ändern.');
|
||||
Response::ok(['message' => 'Admin-Account aktualisiert.']);
|
||||
}
|
||||
|
||||
// === LÖSCHEN ===
|
||||
if ($action === 'delete') {
|
||||
$id = (int)($body['id'] ?? 0);
|
||||
if (!$id) Response::error('ID fehlt.');
|
||||
if ($id === $meId) Response::error('Du kannst deinen eigenen Account nicht löschen.');
|
||||
|
||||
$row = $db->fetchOne('SELECT COUNT(*) AS c FROM admin_users');
|
||||
if ((int)($row['c'] ?? 0) <= 1) {
|
||||
Response::error('Der letzte Admin-Account kann nicht gelöscht werden.');
|
||||
}
|
||||
|
||||
$db->execute('DELETE FROM admin_users WHERE id = ?', [$id]);
|
||||
$db->execute('DELETE FROM admin_pins WHERE admin_id = ?', [$id]); // verwaiste PINs aufräumen
|
||||
Response::ok(['message' => 'Admin-Account gelöscht.']);
|
||||
}
|
||||
|
||||
Response::error('Unbekannte Aktion.');
|
||||
@@ -27,7 +27,9 @@ if ($action === 'register') {
|
||||
$existing = $db->fetchOne('SELECT id FROM teachers WHERE email = ?', [$email]);
|
||||
if ($existing) Response::error('Diese E-Mail-Adresse ist bereits registriert');
|
||||
|
||||
$username = strtolower(explode('@', $email)[0]) . '_' . rand(100, 999);
|
||||
// Regel (ab 2026-08): Der Benutzername einer Lehrperson IST ihre E-Mail-Adresse.
|
||||
// Bestehende, abweichende Benutzernamen bleiben gültig (Login akzeptiert E-Mail ODER Benutzername).
|
||||
$username = strtolower($email);
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
$db->execute(
|
||||
|
||||
Reference in New Issue
Block a user