fix: 4 critical bugs — worker argv, student dashboard visibility, teacher onboarding flow, password validation

This commit is contained in:
Hamza-Ayed
2026-08-28 23:08:15 +03:00
parent abe862f04d
commit 1401db11d0
3 changed files with 41 additions and 39 deletions
@@ -73,9 +73,10 @@ class CurriculumController
error_reporting(E_ALL); error_reporting(E_ALL);
ob_start(); ob_start();
// Execute the script logic natively by setting argv // CRITICAL: Set $GLOBALS['argv'] so the required worker script can access $argv[1]
$argv = ['curriculum_worker.php', $taskId]; // (In a web request, $argv is empty — we must set it globally before requiring the worker)
$_SERVER['argv'] = $argv; $GLOBALS['argv'] = ['curriculum_worker.php', $taskId];
$_SERVER['argv'] = $GLOBALS['argv'];
require $scriptPath; require $scriptPath;
+2 -8
View File
@@ -637,7 +637,7 @@ class StudentPortal
</div> </div>
<!-- 2. STUDENT DASHBOARD (100% REAL DATABASE DATA) --> <!-- 2. STUDENT DASHBOARD (100% REAL DATABASE DATA) -->
<div id="dashboard_container" style="width: 100%;"> <div id="dashboard_container" style="width: 100%; display: none;">
<!-- Hero & Tawjihi Readiness Score --> <!-- Hero & Tawjihi Readiness Score -->
<div class="dashboard-hero"> <div class="dashboard-hero">
@@ -1119,15 +1119,9 @@ class StudentPortal
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
const token = localStorage.getItem('saqel_student_jwt'); const token = localStorage.getItem('saqel_student_jwt');
const cachedUser = localStorage.getItem('saqel_student_user');
if (token) { if (token) {
if (cachedUser) { // Always verify session with server — don't render from cache directly
try {
const u = JSON.parse(cachedUser);
renderDashboard(u);
} catch (e) {}
}
initWebSocket(token); initWebSocket(token);
await checkStudentSession(token); await checkStudentSession(token);
} }
+35 -28
View File
@@ -391,10 +391,8 @@ class TeacherPortal
</select> </select>
</div> </div>
<div class="form-group">
<label class="form-label">تعيين كلمة المرور السرية <span style="color: #EF4444;">*</span></label> <!-- Password field removed: OTP-based auth, no password needed for initial setup -->
<input type="password" id="onboard_password" placeholder="8 خانات على الأقل" class="input-text">
</div>
<button type="button" id="btn_complete_onboarding" onclick="handleCompleteOnboarding(event)" class="btn-primary"> <button type="button" id="btn_complete_onboarding" onclick="handleCompleteOnboarding(event)" class="btn-primary">
<span id="btn_onboard_text">حفظ وتفعيل لوحة التحكم 🚀</span> <span id="btn_onboard_text">حفظ وتفعيل لوحة التحكم 🚀</span>
@@ -665,14 +663,9 @@ class TeacherPortal
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
const token = localStorage.getItem('saqel_teacher_jwt'); const token = localStorage.getItem('saqel_teacher_jwt');
const cachedUser = localStorage.getItem('saqel_teacher_user');
if (token) { if (token) {
if (cachedUser) { // Always verify session first — don't blindly render from cache
try { // checkTeacherSession will render dashboard or show onboarding based on profile status
const u = JSON.parse(cachedUser);
renderDashboard(u, { specialization: u.specialization || 'المعلم المعتمد' });
} catch (e) {}
}
initWebSocket(token); initWebSocket(token);
await checkTeacherSession(token); await checkTeacherSession(token);
} }
@@ -1120,6 +1113,10 @@ class TeacherPortal
} }
function switchToOnboardingStep() { function switchToOnboardingStep() {
// Restore auth container, hide dashboard (renderDashboard may have hidden auth_container)
document.getElementById('auth_container').style.display = 'block';
document.getElementById('dashboard_container').style.display = 'none';
// Show only onboarding step
document.getElementById('step_phone_container').style.display = 'none'; document.getElementById('step_phone_container').style.display = 'none';
document.getElementById('step_otp_container').style.display = 'none'; document.getElementById('step_otp_container').style.display = 'none';
document.getElementById('step_onboarding_container').style.display = 'block'; document.getElementById('step_onboarding_container').style.display = 'block';
@@ -1217,21 +1214,14 @@ class TeacherPortal
if (res.ok && data.status === 'success' && data.data?.token) { if (res.ok && data.status === 'success' && data.data?.token) {
const token = data.data.token; const token = data.data.token;
const user = data.data.user; const user = data.data.user;
const profile = data.data.profile || {};
localStorage.setItem('saqel_teacher_jwt', token); localStorage.setItem('saqel_teacher_jwt', token);
document.cookie = "saqel_teacher_jwt=" + token + "; path=/; max-age=2592000; SameSite=Lax"; document.cookie = "saqel_teacher_jwt=" + token + "; path=/; max-age=2592000; SameSite=Lax";
initWebSocket(token); if (user) {
localStorage.setItem('saqel_teacher_user', JSON.stringify(user));
const isNewTeacher = user?.is_new || user?.full_name === 'معلم جديد' || user?.name === 'معلم جديد' || user?.name === 'الأستاذ المعتمد';
if (isNewTeacher) {
switchToOnboardingStep();
} else {
if (user) {
localStorage.setItem('saqel_teacher_user', JSON.stringify({ ...user, ...profile }));
}
renderDashboard(user, profile);
await checkTeacherSession(token);
} }
initWebSocket(token);
// Let checkTeacherSession decide: if profile is incomplete → onboarding, else → dashboard
await checkTeacherSession(token);
} else { } else {
showError(data.message || 'رمز التحقق غير صحيح'); showError(data.message || 'رمز التحقق غير صحيح');
} }
@@ -1249,12 +1239,22 @@ class TeacherPortal
const token = localStorage.getItem('saqel_teacher_jwt'); const token = localStorage.getItem('saqel_teacher_jwt');
const fullName = document.getElementById('onboard_fullname').value.trim(); const fullName = document.getElementById('onboard_fullname').value.trim();
const spec = document.getElementById('onboard_specialization').value; const spec = document.getElementById('onboard_specialization').value;
const password = document.getElementById('onboard_password').value.trim();
if (!fullName || !password || password.length < 8) { if (!fullName || fullName.length < 3) {
showError('يرجى تعبئة كافة الحقول وكلمة مرور 8 خانات على الأقل'); showError('يرجى إدخال الاسم الكامل للمعلم');
return; return;
} }
if (!spec) {
showError('يرجى تحديد التخصص والمادة');
return;
}
const onboardBtn = document.getElementById('btn_complete_onboarding');
const onboardText = document.getElementById('btn_onboard_text');
const onboardSpinner = document.getElementById('btn_onboard_spinner');
onboardBtn.disabled = true;
onboardText.style.display = 'none';
onboardSpinner.style.display = 'inline-block';
try { try {
const res = await fetch('/api/teacher/profile/setup', { const res = await fetch('/api/teacher/profile/setup', {
@@ -1263,16 +1263,23 @@ class TeacherPortal
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token 'Authorization': 'Bearer ' + token
}, },
body: JSON.stringify({ full_name: fullName, specialization: spec, password: password }) body: JSON.stringify({ full_name: fullName, specialization: spec })
}); });
const data = await res.json(); const data = await res.json();
if (res.ok && data.status === 'success') { if (res.ok && data.status === 'success') {
const u = { full_name: fullName, specialization: spec }; const u = { full_name: fullName, specialization: spec };
localStorage.setItem('saqel_teacher_user', JSON.stringify(u)); localStorage.setItem('saqel_teacher_user', JSON.stringify(u));
renderDashboard(u, { specialization: spec }); renderDashboard(u, { specialization: spec });
showLuxuryToast('أهلاً بك أستاذنا! 🎓', 'تم تفعيل ملفك الأكاديمي بنجاح.');
} else {
showError(data.message || 'فشل حفظ البيانات');
} }
} catch (e) { } catch (e) {
showError('فشل حفظ الملف.'); showError('تعذر الاتصال بالسيرفر. يرجى المحاولة مجدداً.');
} finally {
onboardBtn.disabled = false;
onboardText.style.display = 'inline';
onboardSpinner.style.display = 'none';
} }
} }