9a61f55cb1
- Design-System (assets/css/design-system.css) mit 21 Komponenten, iPad-Responsive-Breakpoints, Touch-Ziele 36px, Music-Player, Glossar-Tooltips - Templates (sims/template.html + student/teacher-Dashboard) - Docs: module-interface.md (inkl. 4a Sprachregel, 4b Leichte Sprache, 4c iPad), content-architecture.md, crash-recovery.md, music-registry.md - Admin-Infrastruktur: admin-modules.html + api/admin-modules.php (Titel, Emoji, Bild, Status, Dauer, Alter pro Modul) - Inbox-System: _inbox/README.md + _status.md fuer Atlas + Briefings an Klima, Glossar, Lehrplan, Fluss - Zentrale SFX-Pipeline (scripts/generate-sounds.py) - DALL-E-Bilder: 8 Badges + 5 Glossar-Repraesentationsbilder (Querformat) - Logo + Inter-Font lokal - PHP-APIs: admin, glossar, levels, licenses, progress, waypoints, assignments, profile, tickets - Spielsprache entfernt (admin-modules, admin-levels, schueler) - Landing-Page-Bearbeitungen (Boote sichtbarer, Button-Hintergrund) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
94 lines
3.5 KiB
PHP
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 (empty($_SESSION['admin_id'])) {
|
|
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);
|
|
}
|