Files
geograsim/App/php/api/admin-modules.php
T
Adminator 37f6238d05 Auth Phase 2: Session-Zugriffe kanalisieren (verhaltensneutral)
Vorbereitung für den JWT+Redis-Umschalter: alle verstreuten
$_SESSION['teacher_id'|admin_id']-Zugriffe laufen jetzt durch Session::-Helper,
damit der Backend-Tausch später EINE Datei (Session.php) ist statt 18 Stellen.

- Session.php: neue Admin-Helper adminId()/loginAdmin()/logoutAdmin()/
  requireAdmin() (mirror der Teacher-Helper). teacherId()/adminId() starten
  die Session jetzt lazy (Aufrufer müssen Session::start() nicht mehr).
- 18 Fundstellen kanalisiert (admin.php, admin-accounts, admin-modules,
  licenses, levels, waypoints, foto-upload, admin_gate, save_map).
- Country.php + app.php cockpit_href: über Session:: mit class_exists-Fallback
  (Bootstrap/Lib-Kontext, Session evtl. nicht geladen).

Verhaltensneutral: 14/14 Lint OK, Helper-Round-Trip 6/6 PASS, Live-Smoke
(admin status/modules/accounts/licenses) weist unauth. Requests wie bisher
mit 401/403 ab. AUTH_BACKEND bleibt 'session' — Live unverändert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-18 16:33:14 +02:00

94 lines
3.5 KiB
PHP

<?php
/**
* Admin API: Module-Verwaltung
* GET /api/admin-modules → Liste aller Module (mit Emoji, Titel, Bild, Status)
* PUT /api/admin-modules → Ein Modul aktualisieren (Emoji, Titel, Subtitle, Status, Bild)
* POST /api/admin-modules → Upload eines neuen Card-Bildes (multipart)
*
* Auth: Super-Admin Session ($_SESSION['admin_id'])
*/
if (session_status() === PHP_SESSION_NONE) session_start();
if (!Session::adminId()) {
http_response_code(401);
echo json_encode(['error' => 'Nicht eingeloggt']);
exit;
}
$db = Database::get();
$method = $_SERVER['REQUEST_METHOD'];
try {
// === GET: Liste aller Module ===
if ($method === 'GET') {
$modules = $db->fetchAll('
SELECT module_id, title, subtitle, icon, card_image, status,
duration_min, age_min, age_max, play_url, page_url, sort_order
FROM module_info
ORDER BY sort_order, title
');
Response::json(['modules' => $modules]);
}
// === PUT: Modul aktualisieren ===
if ($method === 'PUT') {
$body = json_decode(file_get_contents('php://input'), true);
$id = trim($body['module_id'] ?? '');
if (!$id) Response::error('module_id fehlt');
$exists = $db->fetchOne('SELECT module_id FROM module_info WHERE module_id = ?', [$id]);
if (!$exists) Response::error('Modul nicht gefunden', 404);
$fields = [];
$params = [];
// Erlaubte Felder
$allowed = ['title', 'subtitle', 'icon', 'card_image', 'status',
'duration_min', 'age_min', 'age_max', 'play_url', 'page_url', 'sort_order'];
foreach ($allowed as $f) {
if (array_key_exists($f, $body)) {
$fields[] = "$f = ?";
$params[] = $body[$f] === '' ? null : $body[$f];
}
}
if (!$fields) Response::error('Keine Felder zum Aktualisieren');
$params[] = $id;
$sql = 'UPDATE module_info SET ' . implode(', ', $fields) . ' WHERE module_id = ?';
$db->execute($sql, $params);
$updated = $db->fetchOne('SELECT * FROM module_info WHERE module_id = ?', [$id]);
Response::json(['ok' => true, 'module' => $updated]);
}
// === POST: Bild-Upload ===
if ($method === 'POST') {
$id = trim($_POST['module_id'] ?? '');
if (!$id) Response::error('module_id fehlt');
if (empty($_FILES['image'])) Response::error('Kein Bild hochgeladen');
$file = $_FILES['image'];
if ($file['error'] !== UPLOAD_ERR_OK) Response::error('Upload-Fehler');
if ($file['size'] > 5 * 1024 * 1024) Response::error('Bild zu gross (max 5 MB)');
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, ['png', 'jpg', 'jpeg', 'webp', 'svg'])) Response::error('Nur PNG, JPG, WEBP, SVG');
$targetDir = __DIR__ . '/../../assets/img/';
$filename = 'card-' . preg_replace('/[^a-z0-9]/', '', $id) . '.' . $ext;
$targetPath = $targetDir . $filename;
if (!move_uploaded_file($file['tmp_name'], $targetPath)) {
Response::error('Datei konnte nicht gespeichert werden');
}
$db->execute('UPDATE module_info SET card_image = ? WHERE module_id = ?', [$filename, $id]);
Response::json(['ok' => true, 'card_image' => $filename]);
}
Response::error('Methode nicht unterstützt', 405);
} catch (Throwable $e) {
Response::error('Fehler: ' . $e->getMessage(), 500);
}