Update Saqel Platform: 2026-09-08 17:30:46

This commit is contained in:
Hamza-Ayed
2026-09-08 17:30:46 +03:00
parent 5fd1f32d4c
commit 902cf00152
12 changed files with 333 additions and 9 deletions
@@ -98,6 +98,24 @@ class VideoController
return;
}
// No Cloudflare R2 write occurs before this fail-closed media gate.
// The report is generated from the real uploaded file while it remains
// in PHP's temporary storage.
$preflight = AiVideoAnalyzerService::auditUploadBeforeStorage(
$_FILES['video'],
$title,
trim((string)($request->getBody()['subject'] ?? $_POST['subject'] ?? ''))
);
$auditId = $this->recordUploadAudit($request, $courseId, $_FILES['video'], $preflight);
if (($preflight['decision'] ?? '') !== 'approved') {
$response->status(422)->json([
'status' => 'needs_review',
'message' => 'لم يتم حفظ الفيديو في Cloudflare R2 قبل اجتياز تدقيق الجودة.',
'data' => ['audit_id' => $auditId, 'preflight_report' => $preflight],
]);
return;
}
try {
$uploadResult = VideoService::handleDirectUpload($_FILES['video'], $courseId, $title);
@@ -116,6 +134,9 @@ class VideoController
$uploadResult['duration'] ?? 0
]
);
if ($auditId) {
Database::query('UPDATE video_upload_audits SET lesson_id = ? WHERE id = ?', [$lessonId, $auditId]);
}
// Autonomous Zero-Touch AI Analysis & Socratic Checkpoint Generation (Silent Background Execution)
$aiReport = AiVideoAnalyzerService::processLessonAutonomously($lessonId);
@@ -128,6 +149,8 @@ class VideoController
'title' => $title,
'course_id' => $courseId,
'ai_analysis' => $aiReport
,'preflight_report' => $preflight,
'audit_id' => $auditId,
])
]);
} catch (\Throwable $e) {
@@ -138,6 +161,21 @@ class VideoController
}
}
private function recordUploadAudit(Request $request, int $courseId, array $file, array $report): ?int
{
try {
$hex = bin2hex(random_bytes(16));
$uuid = substr($hex, 0, 8) . '-' . substr($hex, 8, 4) . '-4' . substr($hex, 13, 3) . '-a' . substr($hex, 17, 3) . '-' . substr($hex, 20);
return (int)Database::insert(
'INSERT INTO video_upload_audits (uuid, teacher_id, course_id, file_sha256, original_filename, decision, report_json) VALUES (?, ?, ?, ?, ?, ?, ?)',
[$uuid, (int)$request->user_id, $courseId ?: null, hash_file('sha256', (string)($file['tmp_name'] ?? '')), (string)($file['name'] ?? 'video'), (string)($report['decision'] ?? 'needs_manual_review'), json_encode($report, JSON_UNESCAPED_UNICODE)]
);
} catch (\Throwable $e) {
error_log('Video upload audit persistence failed: ' . $e->getMessage());
return null;
}
}
/**
* Create video entity on Bunny Stream
* POST /api/teacher/videos/bunny-create