Files
Adminator ff889865e1 Lizenz-Gate: Schueler ohne Lizenz gesperrt + Lehrer-Cockpit-Warnung
Teil 1 — Schueler-Lizenz-Gate (gilt fuer alle Klassen-Schueler ohne gueltige
Lizenz = zugewiesen, nicht storniert, nicht abgelaufen):
- Server-Gate zentral im Front-Controller (index.php + php/lib/license_gate.php):
  eingeloggte Klassen-Schueler ohne Lizenz sehen bei JEDER Sim-Route statt der
  Simulation eine Hinweis-Seite "Deine Lehrperson muss dir noch eine gueltige
  Lizenz zuweisen". Schnell-Ausstieg fuer Nicht-Schueler/Nicht-Sim (kein Cookie
  -> keine DB-Abfrage). Autodidakt ohne Klasse: nicht lizenzpflichtig.
- modules.php?student=1 liefert 'licensed'; Schueler-Cockpit (schueler.html)
  zeigt oben die Meldung und sperrt die Start-Buttons.

Teil 2 — Lehrer-Cockpit:
- Rote Warnleiste ganz oben, wenn Schueler:innen ohne gueltige Lizenz in der
  Klasse sind (+ Link "Jetzt zuweisen"). licenses?class_id=X liefert dazu die
  Liste 'unlicensed'.
- Lizenzen-Lasche: neue Sektion "Ohne gueltige Lizenz" mit Einzel- und
  Sammel-Zuweisung (auto_assign) — sonst fuehrt die Warnung ins Leere.

Kunden-Vereinfachung (Feedback): keine Auto-Erkennung/Dedup mehr (Ansprech-
partner koennen wechseln). Kunde = Freitext "Name/Verlag/Schule" + Mailadresse,
je Bestellung gespeichert. Editierbares Kundennummer-Feld + Autocomplete entfernt.

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

80 lines
3.3 KiB
PHP

<?php
/**
* Lizenz-Gate — eingeloggte Schüler:innen (in einer Klasse) ohne gültige Lizenz
* sehen bei Sim-Routen statt der Simulation eine Hinweis-Seite. Zentral im
* Front-Controller aufgerufen, damit alle Sim-Wrapper auf einmal geschützt sind.
*
* „Gültige Lizenz" = dem Kind zugewiesen, NICHT storniert und NICHT abgelaufen
* (valid_until >= heute; NULL = Alt-Code ohne Ablauf).
*/
function ggs_student_has_valid_license(PDO $pdo, int $studentId): bool {
if ($studentId <= 0) return false;
$st = $pdo->prepare(
"SELECT 1 FROM licenses
WHERE student_id = ? AND canceled_at IS NULL
AND (valid_until IS NULL OR valid_until >= CURDATE())
LIMIT 1"
);
$st->execute([$studentId]);
return (bool)$st->fetchColumn();
}
/** Ist die Route eine spielbare Sim (play_url ODER module_id, aktiv/beta)? */
function ggs_is_sim_route(PDO $pdo, string $route): bool {
if ($route === '') return false;
$st = $pdo->prepare(
"SELECT 1 FROM module_info
WHERE (play_url = ? OR module_id = ?) AND status IN ('aktiv','beta') LIMIT 1"
);
$st->execute([$route, $route]);
return (bool)$st->fetchColumn();
}
/**
* Front-Controller-Hook: blockt Sim-Zugriff eingeloggter Klassen-Schüler ohne
* gültige Lizenz. Schnell-Ausstieg fuer alle anderen (kein Cookie / keine Sim).
*/
function ggs_license_gate(string $route): void {
$sessionId = $_COOKIE['ggs_session'] ?? null;
if (!$sessionId) return; // nur eingeloggte Schüler:innen
$pdo = getDB();
$st = $pdo->prepare('SELECT student_id, class_id FROM student_sessions WHERE id = ?');
$st->execute([$sessionId]);
$sess = $st->fetch(PDO::FETCH_ASSOC);
if (!$sess || empty($sess['class_id'])) return; // Autodidakt ohne Klasse: nicht im Lizenzmodell
if (!ggs_is_sim_route($pdo, $route)) return; // keine Sim-Route
$studentId = (int)($sess['student_id'] ?? 0);
if (ggs_student_has_valid_license($pdo, $studentId)) return;
ggs_render_license_wall(); // beendet die Anfrage
}
function ggs_render_license_wall(): void {
http_response_code(403);
header('Content-Type: text/html; charset=utf-8');
$css = BASE_PATH . '/assets/css/design-system.css';
$cockpit = BASE_PATH . '/schueler';
echo <<<HTML
<!DOCTYPE html><html lang="de"><head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Lizenz benötigt · GeoGraSim</title>
<link rel="stylesheet" href="{$css}">
<style>
body{font-family:system-ui,-apple-system,'Segoe UI',sans-serif;padding:40px 20px;max-width:620px;margin:auto;color:#2a2a2a}
h1{color:#1f4e5a;font-size:1.4rem;margin:0 0 .6rem}
.lic-card{background:#f2f8f9;border:1px solid #cfe3e8;border-left:5px solid #4a7c8a;padding:26px;border-radius:12px}
.lic-card p{line-height:1.6;margin:.5rem 0}
.lic-card a{color:#4a7c8a;font-weight:700}
.big{font-size:2.2rem;margin-bottom:.2rem}
</style></head><body>
<div class="lic-card">
<div class="big">🔑</div>
<h1>Noch keine Lizenz</h1>
<p><strong>Deine Lehrperson muss dir noch eine gültige Lizenz zuweisen.</strong></p>
<p>Sobald das erledigt ist, kannst du alle freigegebenen Simulationen nutzen.</p>
<p style="margin-top:1rem"><a href="{$cockpit}">← Zurück zum Cockpit</a></p>
</div></body></html>
HTML;
exit;
}