feat(grade10): add chemistry, biology, and earth sciences virtual labs, fix video CDN playback, teacher submissions SQL, and enable authenticated lesson reading
This commit is contained in:
@@ -57,7 +57,7 @@ class VideoController
|
||||
try {
|
||||
$row = Database::selectOne(
|
||||
"SELECT vv.uuid AS video_version_id, l.id AS lesson_id, l.course_id, l.storage_type, l.video_uuid, l.hls_url, l.ai_video_url, l.bunny_video_id, l.duration_seconds,
|
||||
cl.uuid AS curriculum_lesson_id, cl.title, ts.uuid AS submission_id
|
||||
cl.uuid AS curriculum_lesson_id, cl.title, cl.grade_key, ts.uuid AS submission_id
|
||||
FROM video_versions vv
|
||||
JOIN teacher_submissions ts ON ts.id=vv.teacher_submission_id AND ts.current_published_video_version_id=vv.id AND ts.status='published'
|
||||
JOIN curriculum_lessons cl ON cl.id=ts.curriculum_lesson_id
|
||||
@@ -65,12 +65,14 @@ class VideoController
|
||||
WHERE vv.uuid=? AND vv.status='published' LIMIT 1", [$versionUuid]
|
||||
);
|
||||
if (!$row) { $response->status(404)->json(['status'=>'error','message'=>'نسخة الفيديو المطلوبة غير منشورة أو سُحبت.']); return; }
|
||||
$course=Database::selectOne('SELECT grade_level FROM courses WHERE id=? LIMIT 1',[$row['course_id']]);
|
||||
$access=\App\Services\StudentAccessControlService::validateLessonAccess((int)$request->user_id, $request->getHeader('x-national-id'), \App\Services\StudentAccessControlService::normalizeGrade($course['grade_level'] ?? 'grade_10'), (int)$row['course_id'], (int)$row['lesson_id']);
|
||||
$course=Database::selectOne('SELECT grade_level, price_jod FROM courses WHERE id=? LIMIT 1',[$row['course_id']]);
|
||||
$effectiveGrade = \App\Services\StudentAccessControlService::normalizeGrade($row['grade_key'] ?? $course['grade_level'] ?? 'grade_10');
|
||||
$access=\App\Services\StudentAccessControlService::validateLessonAccess((int)$request->user_id, $request->getHeader('x-national-id'), $effectiveGrade, (int)$row['course_id'], (int)$row['lesson_id']);
|
||||
if (empty($access['allowed'])) { $response->status(403)->json(['status'=>'forbidden','message'=>$access['message'] ?? 'غير مصرح بمشاهدة هذه الحصة.']); return; }
|
||||
if ($row['storage_type']==='api_upload') $playback=['storage_type'=>'api_upload','video_url'=>$row['hls_url'] ?: '/api/videos/stream/'.$row['video_uuid'],'hls_url'=>$row['hls_url'] ?: '/api/videos/hls/'.$row['video_uuid'].'/index.m3u8'];
|
||||
elseif (!empty($row['bunny_video_id'])) $playback=array_merge(['storage_type'=>'bunny_stream'],VideoService::generateBunnySignedPlayback($row['bunny_video_id'],10800));
|
||||
elseif (!empty($row['ai_video_url'])) $playback=['storage_type'=>'direct_url','video_url'=>$row['ai_video_url'],'hls_url'=>$row['ai_video_url']];
|
||||
elseif (!empty($row['hls_url'])) $playback=['storage_type'=>'cdn_hls','video_url'=>$row['hls_url'],'hls_url'=>$row['hls_url']];
|
||||
else { $response->status(409)->json(['status'=>'error','message'=>'تخزين نسخة الفيديو غير جاهز.']); return; }
|
||||
$response->json(['status'=>'success','data'=>['video_version_id'=>$row['video_version_id'],'submission_id'=>$row['submission_id'],'curriculum_lesson_id'=>$row['curriculum_lesson_id'],'lesson_id'=>(int)$row['lesson_id'],'title'=>$row['title'],'duration_seconds'=>(int)$row['duration_seconds'],'playback'=>$playback,'checkpoints'=>[]]]);
|
||||
} catch (\Throwable $e) { error_log('Version playback failed: '.$e->getMessage()); $response->status(503)->json(['status'=>'unavailable','message'=>'تعذر تجهيز تشغيل نسخة الفيديو.']); }
|
||||
@@ -80,19 +82,26 @@ class VideoController
|
||||
public function listTeacherSubmissions(Request $request, Response $response): void
|
||||
{
|
||||
$teacherId = (int)$request->user_id;
|
||||
if (!empty($request->identity_id)) {
|
||||
$t = Database::selectOne("SELECT id FROM teachers WHERE identity_id = ? LIMIT 1", [$request->identity_id]);
|
||||
if ($t) {
|
||||
$teacherId = (int)$t['id'];
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$rows = Database::select(
|
||||
"SELECT ts.id AS submission_id, ts.uuid AS submission_uuid, ts.status AS submission_status,
|
||||
ts.current_published_video_version_id, ts.created_at, ts.updated_at,
|
||||
cl.id AS lesson_id, cl.uuid AS curriculum_lesson_uuid, cl.title AS lesson_title,
|
||||
cl.subject_key, cl.grade_level, cl.semester_key, cl.unit_key, cl.lesson_key,
|
||||
cl.subject_key, cl.grade_key, cl.grade_key AS grade_level, cl.semester_key, cl.unit_key, cl.lesson_key,
|
||||
vv.id AS video_version_id, vv.uuid AS video_version_uuid, vv.version_number,
|
||||
vv.status AS video_status, vv.published_at, vv.created_at AS version_created_at
|
||||
FROM teacher_submissions ts
|
||||
JOIN curriculum_lessons cl ON cl.id = ts.curriculum_lesson_id
|
||||
LEFT JOIN video_versions vv ON vv.teacher_submission_id = ts.id
|
||||
WHERE ts.teacher_id = ?
|
||||
ORDER BY ts.updated_at DESC, vv.version_number DESC",
|
||||
FROM teacher_submissions ts
|
||||
JOIN curriculum_lessons cl ON cl.id = ts.curriculum_lesson_id
|
||||
LEFT JOIN video_versions vv ON vv.teacher_submission_id = ts.id
|
||||
WHERE ts.teacher_id = ?
|
||||
ORDER BY ts.updated_at DESC, vv.version_number DESC",
|
||||
[$teacherId]
|
||||
);
|
||||
|
||||
@@ -152,13 +161,14 @@ class VideoController
|
||||
$response->status(400)->json(['status' => 'error', 'message' => 'هوية الدرس غير صالحة.']); return;
|
||||
}
|
||||
try {
|
||||
$lesson = Database::selectOne("SELECT id, uuid, title FROM curriculum_lessons WHERE uuid = ? AND source_status = 'approved' LIMIT 1", [$lessonUuid]);
|
||||
$lesson = Database::selectOne("SELECT id, uuid, title, grade_key FROM curriculum_lessons WHERE uuid = ? AND source_status = 'approved' LIMIT 1", [$lessonUuid]);
|
||||
if (!$lesson) { $response->status(404)->json(['status'=>'error','message'=>'الدرس غير منشور.']); return; }
|
||||
$rows = Database::select(
|
||||
"SELECT vv.id, vv.uuid AS video_version_id, vv.source_lesson_id, ts.uuid AS submission_id,
|
||||
c.grade_level, l.course_id, t.full_name AS teacher_name, COALESCE(pm.weighted_student_rating, 0) AS rating,
|
||||
cl.grade_key, c.grade_level AS course_grade_level, l.course_id, t.full_name AS teacher_name, COALESCE(pm.weighted_student_rating, 0) AS rating,
|
||||
COALESCE(pm.total_reviews_count, 0) AS rating_count
|
||||
FROM teacher_submissions ts
|
||||
JOIN curriculum_lessons cl ON cl.id = ts.curriculum_lesson_id
|
||||
JOIN video_versions vv ON vv.id = ts.current_published_video_version_id AND vv.status = 'published'
|
||||
JOIN lessons l ON l.id = vv.source_lesson_id AND l.encoding_status = 'ready'
|
||||
JOIN courses c ON c.id = l.course_id
|
||||
@@ -173,10 +183,11 @@ class VideoController
|
||||
// legitimately have versions attached to different courses.
|
||||
$accessible = [];
|
||||
foreach ($rows as $row) {
|
||||
$targetGrade = \App\Services\StudentAccessControlService::normalizeGrade($row['grade_key'] ?? $lesson['grade_key'] ?? 'grade_10');
|
||||
$access = \App\Services\StudentAccessControlService::validateLessonAccess(
|
||||
(int)$request->user_id,
|
||||
$request->getHeader('x-national-id'),
|
||||
\App\Services\StudentAccessControlService::normalizeGrade($row['grade_level'] ?? 'grade_10'),
|
||||
$targetGrade,
|
||||
(int)$row['course_id'],
|
||||
(int)$row['source_lesson_id'],
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user