1e51ef7def
- 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>
141 lines
4.9 KiB
PHP
141 lines
4.9 KiB
PHP
<?php
|
|
/**
|
|
* API: Logistik-Sessions (Durchgangs-Tracking)
|
|
*
|
|
* POST /api/logistik-sessions {action: "start", levelId: 2}
|
|
* -> legt einen aktiven Durchgang an, liefert attempt_id zurueck
|
|
*
|
|
* POST /api/logistik-sessions {action: "end", attemptId, finalBalance, success, stats}
|
|
* -> schliesst den Durchgang ab
|
|
*
|
|
* GET /api/logistik-sessions?action=status
|
|
* -> liefert aktiven Durchgang der aktuellen Schueler-Session (oder null)
|
|
*
|
|
* Persistenz: nutzt game_saves (save_key = "logistik:active-attempt" +
|
|
* "logistik:history") — keine eigene Tabelle noetig.
|
|
*
|
|
* Security: Session-ID aus Cookie wird gegen student_sessions validiert.
|
|
*/
|
|
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
$db = Database::get();
|
|
|
|
/** Student-Session validieren (nicht nur Cookie-Praesenz, sondern DB-Existenz). */
|
|
function lg_requireValidStudent(): string {
|
|
$sid = Session::requireStudent();
|
|
$db = Database::get();
|
|
$row = $db->fetchOne('SELECT id FROM student_sessions WHERE id = ?', [$sid]);
|
|
if (!$row) {
|
|
http_response_code(401);
|
|
echo json_encode(['error' => 'Session ungueltig']);
|
|
exit;
|
|
}
|
|
return $sid;
|
|
}
|
|
|
|
function lg_uuid(): string {
|
|
return sprintf('%s-%s-%s-%s-%s',
|
|
bin2hex(random_bytes(4)),
|
|
bin2hex(random_bytes(2)),
|
|
bin2hex(random_bytes(2)),
|
|
bin2hex(random_bytes(2)),
|
|
bin2hex(random_bytes(6))
|
|
);
|
|
}
|
|
|
|
if ($method === 'GET') {
|
|
$action = $_GET['action'] ?? 'status';
|
|
if ($action !== 'status') Response::error('Unbekannte Aktion', 400);
|
|
|
|
$sid = lg_requireValidStudent();
|
|
$row = $db->fetchOne(
|
|
'SELECT save_data FROM game_saves WHERE session_id = ? AND save_key = ?',
|
|
[$sid, 'logistik:active-attempt']
|
|
);
|
|
if (!$row) Response::ok(['active' => null]);
|
|
$payload = json_decode($row['save_data'], true);
|
|
Response::ok(['active' => $payload]);
|
|
}
|
|
|
|
if ($method === 'POST') {
|
|
$body = json_decode(file_get_contents('php://input'), true);
|
|
if (!is_array($body)) Response::error('Body fehlt oder kein JSON', 400);
|
|
$action = $body['action'] ?? '';
|
|
$sid = lg_requireValidStudent();
|
|
|
|
if ($action === 'start') {
|
|
$levelId = (int)($body['levelId'] ?? 0);
|
|
if ($levelId < 1) Response::error('levelId fehlt oder ungueltig', 400);
|
|
|
|
$attemptId = lg_uuid();
|
|
$payload = [
|
|
'attemptId' => $attemptId,
|
|
'levelId' => $levelId,
|
|
'startedAt' => gmdate('c'),
|
|
'status' => 'active',
|
|
];
|
|
|
|
$db->execute(
|
|
'INSERT INTO game_saves (session_id, save_key, save_data, save_version)
|
|
VALUES (?, ?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE save_data = VALUES(save_data), save_version = VALUES(save_version)',
|
|
[$sid, 'logistik:active-attempt', json_encode($payload), 1]
|
|
);
|
|
|
|
Response::ok(['attemptId' => $attemptId, 'levelId' => $levelId]);
|
|
}
|
|
|
|
if ($action === 'end') {
|
|
$attemptId = trim($body['attemptId'] ?? '');
|
|
if (strlen($attemptId) < 8) Response::error('attemptId fehlt', 400);
|
|
|
|
$row = $db->fetchOne(
|
|
'SELECT save_data FROM game_saves WHERE session_id = ? AND save_key = ?',
|
|
[$sid, 'logistik:active-attempt']
|
|
);
|
|
if (!$row) Response::error('Kein aktiver Durchgang', 404);
|
|
$active = json_decode($row['save_data'], true);
|
|
if (($active['attemptId'] ?? null) !== $attemptId) {
|
|
Response::error('attemptId passt nicht zum aktiven Durchgang', 409);
|
|
}
|
|
|
|
$finalBalance = (int)($body['finalBalance'] ?? 0);
|
|
$success = (bool)($body['success'] ?? false);
|
|
$stats = is_array($body['stats'] ?? null) ? $body['stats'] : [];
|
|
|
|
$closed = array_merge($active, [
|
|
'status' => $success ? 'success' : 'fail',
|
|
'finalBalance' => $finalBalance,
|
|
'endedAt' => gmdate('c'),
|
|
'stats' => $stats,
|
|
]);
|
|
|
|
// Aktiven Slot leeren, Historie anhaengen (letzte 20 Durchgaenge)
|
|
$db->execute(
|
|
'DELETE FROM game_saves WHERE session_id = ? AND save_key = ?',
|
|
[$sid, 'logistik:active-attempt']
|
|
);
|
|
|
|
$hist = $db->fetchOne(
|
|
'SELECT save_data FROM game_saves WHERE session_id = ? AND save_key = ?',
|
|
[$sid, 'logistik:history']
|
|
);
|
|
$list = $hist ? (json_decode($hist['save_data'], true) ?: []) : [];
|
|
$list[] = $closed;
|
|
if (count($list) > 20) $list = array_slice($list, -20);
|
|
|
|
$db->execute(
|
|
'INSERT INTO game_saves (session_id, save_key, save_data, save_version)
|
|
VALUES (?, ?, ?, ?)
|
|
ON DUPLICATE KEY UPDATE save_data = VALUES(save_data), save_version = VALUES(save_version)',
|
|
[$sid, 'logistik:history', json_encode($list), 1]
|
|
);
|
|
|
|
Response::ok(['closed' => $closed]);
|
|
}
|
|
|
|
Response::error('Unbekannte Aktion', 400);
|
|
}
|
|
|
|
Response::error('Methode nicht erlaubt', 405);
|