feat: Add collapsible curriculum accordion tree, direct video upload to platform, resilient AI asset generation with smart synthesis fallback, and ingest Physics Unit 2

This commit is contained in:
Hamza-Ayed
2026-08-29 05:13:47 +03:00
parent 4e047ee8f2
commit 771ec6acc5
13 changed files with 869 additions and 301 deletions
@@ -228,4 +228,49 @@ class CurriculumController
$response->status(500)->json(['status' => 'error', 'message' => 'فشل توليد المخرجات الذكية']);
}
}
/**
* Direct Video Upload to Platform Storage
*/
public function uploadLessonVideo(Request $request, Response $response): void
{
$file = $_POST['file'] ?? '';
if (empty($file)) {
$response->status(400)->json(['status' => 'error', 'message' => 'مسار الدرس مطلوب']);
return;
}
if (empty($_FILES['video_file']) || $_FILES['video_file']['error'] !== UPLOAD_ERR_OK) {
$response->status(400)->json(['status' => 'error', 'message' => 'يرجى اختيار ملف فيديو صالح (MP4, WebM, MOV)']);
return;
}
$uploadDir = __DIR__ . '/../../public/uploads/curriculum_videos';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$videoTmp = $_FILES['video_file']['tmp_name'];
$ext = strtolower(pathinfo($_FILES['video_file']['name'], PATHINFO_EXTENSION)) ?: 'mp4';
$safeName = 'video_' . md5($file) . '_' . time() . '.' . $ext;
$destPath = $uploadDir . '/' . $safeName;
if (!move_uploaded_file($videoTmp, $destPath)) {
$response->status(500)->json(['status' => 'error', 'message' => 'تعذر رفع وحفظ ملف الفيديو على السيرفر']);
return;
}
$videoUrl = '/uploads/curriculum_videos/' . $safeName;
// Automatically update AI assets with the new video URL
$currentAssets = CurriculumService::getLessonAiAssets($file);
$currentAssets['ai_video_url'] = $videoUrl;
CurriculumService::saveLessonAiAssets($file, $currentAssets);
$response->json([
'status' => 'success',
'message' => 'تم رفع وتثبيت فيديو الشرح على منصة صَقِل بنجاح!',
'video_url' => $videoUrl
]);
}
}