97 lines
4.3 KiB
PHP
97 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace App\Controllers;
|
|
|
|
use App\Core\Database;
|
|
use App\Core\Request;
|
|
use App\Core\Response;
|
|
|
|
class ErrorNotebookController
|
|
{
|
|
public function getErrorNotebook(Request $request, Response $response): void
|
|
{
|
|
$studentId = (int)$request->user_id;
|
|
$sql = "SELECT * FROM student_error_notebook WHERE student_id = ?";
|
|
$params = [$studentId];
|
|
$subject = trim((string)$request->getQuery('subject', ''));
|
|
$status = trim((string)$request->getQuery('status', ''));
|
|
if ($subject !== '') { $sql .= ' AND subject_id = ?'; $params[] = $subject; }
|
|
if ($status !== '') { $sql .= ' AND status = ?'; $params[] = $status; }
|
|
$items = Database::select($sql . ' ORDER BY created_at DESC', $params);
|
|
|
|
$mastered = count(array_filter($items, fn($item) => ($item['status'] ?? '') === 'mastered'));
|
|
$bySubject = [];
|
|
foreach ($items as $item) {
|
|
$name = (string)($item['subject_name'] ?? '');
|
|
if ($name !== '') $bySubject[$name] = ($bySubject[$name] ?? 0) + 1;
|
|
}
|
|
$total = count($items);
|
|
$response->json(['status' => 'success', 'data' => [
|
|
'summary' => [
|
|
'total_errors' => $total,
|
|
'mastered_count' => $mastered,
|
|
'pending_count' => $total - $mastered,
|
|
'mastery_percentage' => $total ? round(($mastered / $total) * 100, 1) : 0.0,
|
|
'by_subject' => $bySubject,
|
|
],
|
|
'items' => $items,
|
|
]]);
|
|
}
|
|
|
|
public function logError(Request $request, Response $response): void
|
|
{
|
|
$body = $request->getBody();
|
|
foreach (['subject_id', 'subject_name', 'topic_name', 'source_type', 'question_text', 'student_wrong_answer', 'correct_answer'] as $field) {
|
|
if (trim((string)($body[$field] ?? '')) === '') {
|
|
$response->status(422)->json(['status' => 'error', 'message' => "الحقل {$field} مطلوب"]);
|
|
return;
|
|
}
|
|
}
|
|
$uuid = $this->uuid();
|
|
Database::insert(
|
|
"INSERT INTO student_error_notebook
|
|
(uuid, student_id, subject_id, subject_name, topic_name, lesson_id, source_type, question_text, options_json,
|
|
student_wrong_answer, correct_answer, socratic_hint, error_category, status, created_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending_remediation', NOW())",
|
|
[
|
|
$uuid, (int)$request->user_id, $body['subject_id'], $body['subject_name'], $body['topic_name'],
|
|
!empty($body['lesson_id']) ? (int)$body['lesson_id'] : null, $body['source_type'], $body['question_text'],
|
|
isset($body['options']) ? json_encode($body['options'], JSON_UNESCAPED_UNICODE) : null,
|
|
$body['student_wrong_answer'], $body['correct_answer'], (string)($body['socratic_hint'] ?? ''),
|
|
(string)($body['error_category'] ?? 'conceptual'),
|
|
]
|
|
);
|
|
$response->status(201)->json(['status' => 'success', 'uuid' => $uuid]);
|
|
}
|
|
|
|
public function getRemediationQuiz(Request $request, Response $response): void
|
|
{
|
|
$uuid = trim((string)$request->getQuery('error_uuid', ''));
|
|
$error = Database::selectOne(
|
|
"SELECT id FROM student_error_notebook WHERE uuid = ? AND student_id = ? LIMIT 1",
|
|
[$uuid, (int)$request->user_id]
|
|
);
|
|
if (!$error) {
|
|
$response->status(404)->json(['status' => 'error', 'message' => 'الفجوة التعليمية غير موجودة']);
|
|
return;
|
|
}
|
|
$response->status(409)->json(['status' => 'error', 'message' => 'لم يُولّد الخادم اختباراً علاجياً موثقاً لهذه الفجوة بعد']);
|
|
}
|
|
|
|
public function resolveError(Request $request, Response $response): void
|
|
{
|
|
$response->status(409)->json([
|
|
'status' => 'error',
|
|
'message' => 'يتم اعتماد الإتقان حصراً بعد تسليم اختبار علاجي وتصحيحه على الخادم',
|
|
]);
|
|
}
|
|
|
|
private function uuid(): string
|
|
{
|
|
$data = random_bytes(16);
|
|
$data[6] = chr((ord($data[6]) & 0x0f) | 0x40);
|
|
$data[8] = chr((ord($data[8]) & 0x3f) | 0x80);
|
|
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
|
}
|
|
}
|