Files
geograsim/v2-platform/php/api/teacher/students.php
T
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

145 lines
6.6 KiB
PHP

<?php
/**
* GET /api/teacher/students?classId=42 — Liste mit A11y + Nachteilsausgleich
* POST /api/teacher/students — neue Schüler*in anlegen
* PATCH /api/teacher/students — Flag/Property aktualisieren
* DELETE /api/teacher/students?studentId=X — Soft-Delete (deleted_at = NOW())
*/
declare(strict_types=1);
require_once __DIR__ . '/../../bootstrap.php';
$method = v2_validate_method_in(['GET', 'POST', 'PATCH', 'DELETE']);
$auth = v2_auth_require('teacher');
$teacherId = (int) ($auth['sub'] ?? 0);
// Helper: Klassen-Zugehörigkeit prüfen
function class_owned(int $classId, int $teacherId): bool {
return (bool) v2_db_one(
'SELECT id FROM classes WHERE id = :c AND teacher_id = :t',
[':c' => $classId, ':t' => $teacherId]
);
}
function student_owned(int $studentId, int $teacherId): bool {
return (bool) v2_db_one("
SELECT s.id FROM students s
JOIN classes c ON c.id = s.class_id
WHERE s.id = :sid AND c.teacher_id = :tid
", [':sid' => $studentId, ':tid' => $teacherId]);
}
// ── GET ───────────────────────────────────────────────────────────
if ($method === 'GET') {
$classId = (int) ($_GET['classId'] ?? 0);
if (!$classId) v2_response_error(400, 'missing_classId', 'classId fehlt.');
if (!class_owned($classId, $teacherId)) v2_response_error(403, 'forbidden', 'Klasse nicht deine.');
$rows = v2_db_all("
SELECT s.id, s.username, s.display_name, s.avatar_slug, s.first_name, s.last_name,
s.easy_language, s.high_contrast, s.reduced_motion,
s.screen_reader, s.nachteilsausgleich, s.last_login
FROM students s
WHERE s.class_id = :cid AND s.deleted_at IS NULL
ORDER BY s.display_name, s.username
", [':cid' => $classId]);
v2_response_ok(['students' => array_map(fn($r) => [
'id' => (int) $r['id'],
'username' => $r['username'],
'displayName' => $r['display_name'] ?? $r['username'],
'firstName' => $r['first_name'],
'lastName' => $r['last_name'],
'avatarSlug' => $r['avatar_slug'] ?? 'fuchs-explorer',
'easyLanguage' => (bool) $r['easy_language'],
'highContrast' => (bool) $r['high_contrast'],
'reducedMotion' => (bool) $r['reduced_motion'],
'screenReader' => (bool) $r['screen_reader'],
'nachteilsausgleich' => (bool) $r['nachteilsausgleich'],
'lastLogin' => $r['last_login'],
], $rows)]);
}
// ── POST: neue Schüler*in anlegen ────────────────────────────────
if ($method === 'POST') {
$body = v2_request_body_json_required();
v2_validate_required($body, ['classId', 'username', 'password']);
$classId = (int) $body['classId'];
if (!class_owned($classId, $teacherId)) v2_response_error(403, 'forbidden', 'Klasse nicht deine.');
$username = trim((string) $body['username']);
$password = (string) $body['password'];
if (strlen($username) < 2) v2_response_error(400, 'username_too_short', 'Username muss mind. 2 Zeichen haben.');
if (strlen($password) < 4) v2_response_error(400, 'password_too_short', 'Passwort muss mind. 4 Zeichen haben.');
// Username-Uniqueness IN dieser Klasse
$existing = v2_db_one(
'SELECT id FROM students WHERE class_id = :c AND username = :u AND deleted_at IS NULL',
[':c' => $classId, ':u' => $username]
);
if ($existing) v2_response_error(409, 'username_taken', "Username '$username' ist in dieser Klasse schon vergeben.");
$displayName = trim((string) ($body['displayName'] ?? '')) ?: $username;
$firstName = trim((string) ($body['firstName'] ?? '')) ?: null;
$lastName = trim((string) ($body['lastName'] ?? '')) ?: null;
$avatarSlug = trim((string) ($body['avatarSlug'] ?? '')) ?: 'fuchs-explorer';
$easyLang = !empty($body['easyLanguage']) ? 1 : 0;
$nachteil = !empty($body['nachteilsausgleich']) ? 1 : 0;
$hash = password_hash($password, PASSWORD_DEFAULT);
v2_db_exec(
'INSERT INTO students
(class_id, username, password, display_name, first_name, last_name,
avatar_slug, easy_language, nachteilsausgleich, is_anonymous)
VALUES (:cid, :u, :p, :dn, :fn, :ln, :av, :ez, :na, 0)',
[
':cid' => $classId, ':u' => $username, ':p' => $hash,
':dn' => $displayName, ':fn' => $firstName, ':ln' => $lastName,
':av' => $avatarSlug, ':ez' => $easyLang, ':na' => $nachteil,
]
);
v2_response_created([
'id' => (int) v2_db_insert_id(),
'username' => $username,
'displayName' => $displayName,
]);
}
// ── PATCH: Flag/Property updaten ─────────────────────────────────
if ($method === 'PATCH') {
$body = v2_request_body_json_required();
v2_validate_required($body, ['studentId']);
$studentId = (int) $body['studentId'];
if (!student_owned($studentId, $teacherId)) v2_response_error(403, 'forbidden', 'Schüler*in nicht in deiner Klasse.');
$updates = [];
$params = [':id' => $studentId];
foreach (['nachteilsausgleich', 'easyLanguage', 'highContrast', 'reducedMotion', 'screenReader'] as $k) {
if (array_key_exists($k, $body)) {
$col = strtolower(preg_replace('/([A-Z])/', '_$1', $k));
$updates[] = "`$col` = :$col";
$params[":$col"] = $body[$k] ? 1 : 0;
}
}
// Optional auch Anzeigename/Avatar updatable
foreach (['displayName' => 'display_name', 'avatarSlug' => 'avatar_slug',
'firstName' => 'first_name', 'lastName' => 'last_name'] as $k => $col) {
if (array_key_exists($k, $body)) {
$updates[] = "`$col` = :$k";
$params[":$k"] = $body[$k];
}
}
if (empty($updates)) v2_response_error(400, 'no_changes', 'Keine Felder zum Aktualisieren.');
v2_db_exec("UPDATE students SET " . implode(', ', $updates) . " WHERE id = :id", $params);
v2_response_ok(['ok' => true]);
}
// ── DELETE: Soft-Delete ──────────────────────────────────────────
$studentId = (int) ($_GET['studentId'] ?? 0);
if (!$studentId) v2_response_error(400, 'missing_studentId', 'studentId fehlt.');
if (!student_owned($studentId, $teacherId)) v2_response_error(403, 'forbidden', 'Schüler*in nicht in deiner Klasse.');
v2_db_exec('UPDATE students SET deleted_at = NOW() WHERE id = :id', [':id' => $studentId]);
v2_response_ok(['ok' => true]);