Complete Socratic adaptive exams in Flutter, Guardian WhatsApp alerts, and curriculum robustness

This commit is contained in:
Hamza-Ayed
2026-09-03 10:14:34 +03:00
parent ab482d85e4
commit 12049fd7da
12 changed files with 1444 additions and 26 deletions
@@ -85,6 +85,7 @@ class ExamController
*/
public function submitExam(Request $request, Response $response): void
{
self::ensureAttemptSchema();
$studentId = $request->user_id;
$examId = (int)$request->getParam('id');
$body = $request->getBody();
@@ -213,6 +214,40 @@ class ExamController
updated_at = NOW()
", [$studentId, $courseId, $subjectId, $avgMastery, $tawjihiIndex, $passedExams, $totalExams]);
// Trigger Guardian Alert via Nabeh WhatsApp if remediation needed
if (!$passed && !empty($weakTopics)) {
try {
$studentInfo = Database::selectOne(
"SELECT s.full_name, sub.name AS subject_name
FROM students s
LEFT JOIN courses c ON c.id = ?
LEFT JOIN subjects sub ON sub.id = c.subject_id
WHERE s.id = ? LIMIT 1",
[$courseId, $studentId]
);
$guardian = Database::selectOne(
"SELECT ai.phone_number
FROM guardian_students gs
JOIN guardians g ON g.id = gs.guardian_id
JOIN auth_identities ai ON ai.id = g.auth_identity_id
WHERE gs.student_id = ? LIMIT 1",
[$studentId]
);
if ($guardian && !empty($guardian['phone_number'])) {
$nabeh = new \App\Services\NabehService();
$weakTopicStr = implode('، ', array_keys($weakTopics));
$nabeh->sendGuardianRemedialAlert(
(string)$guardian['phone_number'],
$studentInfo['full_name'] ?? 'الطالب',
$studentInfo['subject_name'] ?? 'المبحث المقرر',
$weakTopicStr
);
}
} catch (\Throwable $e) {
error_log("Guardian remedial alert notice: " . $e->getMessage());
}
}
$response->json([
'status' => 'success',
'data' => [
@@ -230,6 +265,23 @@ class ExamController
]);
}
/** Additive production migration for installations created before completed_at. */
private static function ensureAttemptSchema(): void
{
try {
$column = Database::selectOne(
"SELECT COUNT(*) AS cnt FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'exam_attempts'
AND COLUMN_NAME = 'completed_at' LIMIT 1"
);
if (empty($column['cnt'])) {
Database::query("ALTER TABLE exam_attempts ADD COLUMN completed_at TIMESTAMP NULL DEFAULT NULL AFTER ai_diagnostic_report");
}
} catch (\Throwable $e) {
error_log('Exam schema migration note: ' . $e->getMessage());
}
}
/**
* Get Student Mastery & Tawjihi Readiness Analytics
* GET /api/student/progress/mastery?course_id=1