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>
145 lines
6.6 KiB
PHP
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]);
|