Files
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

114 lines
4.6 KiB
PHP

<?php
/**
* GET /api/modules/available
*
* Liefert für die eingeloggte Schüler*in zwei Listen:
* - assignments: aktuelle Modulaufträge der Klasse (fixe Schwierigkeit)
* - freeModules: Module, die für die Klasse generell freigegeben sind
*
* Liest Modul-Stammdaten aus module_info_v2 (V2-Registrierung).
* Aufträge aus class_assignments_v2.
* Freigaben aus V1-class_modules (wird in V2 weiter genutzt).
*/
declare(strict_types=1);
require_once __DIR__ . '/../../bootstrap.php';
v2_validate_method('GET');
$auth = v2_auth_require('student');
$studentId = (int) ($auth['sub'] ?? 0);
$classId = (int) ($auth['class_id'] ?? 0);
// ─── Aktive Aufträge (V2) ────────────────────────────────────────
$assignmentsRaw = v2_db_all("
SELECT a.id, a.module_slug, a.difficulty, a.starts_at, a.ends_at,
mi.display_name, mi.display_name_easy, mi.icon, mi.card_image_url,
mi.short_description, mi.short_description_easy,
mi.estimated_duration_min
FROM class_assignments_v2 a
LEFT JOIN module_info_v2 mi ON mi.slug = a.module_slug
WHERE a.class_id = :cid AND a.active = 1
AND a.starts_at <= NOW()
AND (a.ends_at IS NULL OR a.ends_at > NOW())
ORDER BY a.created_at DESC
", [':cid' => $classId]);
// ─── Freie Module (V1-Freigaben weiter genutzt) ──────────────────
// V1: class_modules.module_id matcht module_info_v2.slug
$freeRaw = [];
try {
$freeRaw = v2_db_all("
SELECT mi.slug, mi.display_name, mi.display_name_easy,
mi.icon, mi.card_image_url, mi.short_description,
mi.short_description_easy, mi.estimated_duration_min,
mi.status
FROM module_info_v2 mi
WHERE mi.status IN ('beta', 'stable')
AND mi.slug IN (
SELECT module_id FROM class_modules WHERE class_id = :cid AND enabled = 1
)
ORDER BY mi.display_name
", [':cid' => $classId]);
} catch (Throwable $e) {
// Fallback: alle 'stable' V2-Module wenn class_modules nicht existiert / leer ist
$freeRaw = v2_db_all("
SELECT slug, display_name, display_name_easy, icon, card_image_url,
short_description, short_description_easy,
estimated_duration_min, status
FROM module_info_v2
WHERE status IN ('beta', 'stable')
ORDER BY display_name
");
}
// ─── Level-Unlocks ───────────────────────────────────────────────
$unlocks = v2_db_all("
SELECT module_slug, highest_unlocked_level, highest_completed_level
FROM student_level_unlock_v2
WHERE student_id = :sid
", [':sid' => $studentId]);
$unlocksBySlug = [];
foreach ($unlocks as $u) {
$unlocksBySlug[$u['module_slug']] = [
'highestUnlocked' => $u['highest_unlocked_level'],
'highestCompleted' => $u['highest_completed_level'],
];
}
// ─── Output formen ───────────────────────────────────────────────
$assignments = array_map(function ($a) {
return [
'assignmentId' => (int) $a['id'],
'moduleSlug' => $a['module_slug'],
'difficulty' => $a['difficulty'],
'displayName' => $a['display_name'] ?? $a['module_slug'],
'displayNameEasy' => $a['display_name_easy'] ?? $a['module_slug'],
'icon' => $a['icon'] ?? '📘',
'cardImageUrl' => $a['card_image_url'],
'shortDescription' => $a['short_description'] ?? '',
'shortDescriptionEasy' => $a['short_description_easy'] ?? '',
'estimatedDurationMin' => (int) ($a['estimated_duration_min'] ?? 0),
'endsAt' => $a['ends_at'],
];
}, $assignmentsRaw);
$freeModules = array_map(function ($m) use ($unlocksBySlug) {
return [
'slug' => $m['slug'],
'displayName' => $m['display_name'],
'displayNameEasy' => $m['display_name_easy'],
'icon' => $m['icon'] ?? '📘',
'cardImageUrl' => $m['card_image_url'],
'shortDescription' => $m['short_description'] ?? '',
'shortDescriptionEasy' => $m['short_description_easy'] ?? '',
'estimatedDurationMin' => (int) ($m['estimated_duration_min'] ?? 0),
'status' => $m['status'],
'unlocked' => $unlocksBySlug[$m['slug']] ?? ['highestUnlocked' => 'L1', 'highestCompleted' => null],
];
}, $freeRaw);
v2_response_ok([
'assignments' => $assignments,
'freeModules' => $freeModules,
]);