Files
saqel/backend/app/Controllers/TeacherController.php
T

304 lines
12 KiB
PHP

<?php
namespace App\Controllers;
use App\Core\Request;
use App\Core\Response;
use App\Core\Database;
use App\Core\Security;
use App\Core\Validator;
use App\Services\CurriculumService;
class TeacherController
{
/**
* Check if Teacher Profile is complete or requires onboarding
* GET /api/teacher/profile/status
*/
public function profileStatus(Request $request, Response $response): void
{
$userId = $request->user_id;
$user = Database::selectOne("SELECT id, uuid, full_name, role, status FROM users WHERE id = ? LIMIT 1", [$userId]);
if (!$user) {
$response->status(404)->json(['status' => 'error', 'message' => 'المعلم غير موجود']);
return;
}
$profile = Database::selectOne("SELECT * FROM teacher_profiles WHERE user_id = ? LIMIT 1", [$userId]);
if (!$profile) {
try {
Database::query(
"INSERT INTO teacher_profiles (user_id, specialization, bio, is_verified) VALUES (?, 'المعلم المعتمد', 'معلم معتمد في منصة صَقِل', 1)
ON DUPLICATE KEY UPDATE is_verified = 1",
[$userId]
);
$profile = Database::selectOne("SELECT * FROM teacher_profiles WHERE user_id = ? LIMIT 1", [$userId]);
} catch (\Exception $e) {
error_log("Auto create teacher profile notice: " . $e->getMessage());
}
}
$rawName = (string)($user['full_name'] ?? '');
$decryptedName = Security::decrypt($rawName) ?: $rawName;
if (empty($decryptedName)) {
$decryptedName = 'معلم صَقِل المعتمد';
}
$response->json([
'status' => 'success',
'is_completed' => true,
'user' => [
'uuid' => $user['uuid'],
'full_name' => $decryptedName,
'role' => $user['role'],
'status' => $user['status'],
],
'profile' => $profile ?: [
'specialization' => 'المعلم المعتمد',
'bio' => 'معلم معتمد في منصة صَقِل'
]
]);
}
/**
* Complete or Update Teacher Onboarding Profile (Password, Name, Bio, Grades, Subjects)
* POST /api/teacher/profile/setup
*/
public function setupProfile(Request $request, Response $response): void
{
$userId = $request->user_id;
$body = $request->getBody();
$validator = new Validator();
$isValid = $validator->validate($body, [
'full_name' => 'required',
'specialization' => 'required',
'password' => 'required|min:8',
]);
if (!$isValid) {
$response->status(400)->json([
'status' => 'error',
'message' => 'بيانات الملف الشخصي غير مكتملة أو كلمة المرور قصيرة (أقل من 8 خانات)',
'errors' => $validator->getErrors()
]);
return;
}
$fullName = trim((string)$body['full_name']);
$specialization = trim((string)$body['specialization']);
$bio = trim((string)($body['bio'] ?? ''));
$gradeLevels = is_array($body['grade_levels'] ?? null) ? implode(',', $body['grade_levels']) : (string)($body['grade_levels'] ?? 'tawjihi_2008');
$passwordHash = Security::hashPassword((string)$body['password']);
// 1. Update User table
$encryptedName = Security::encrypt($fullName);
Database::query(
"UPDATE users SET full_name = ?, password_hash = ?, grade_level = ?, status = 'active' WHERE id = ?",
[$encryptedName, $passwordHash, $gradeLevels, $userId]
);
// 2. Upsert Teacher Profile
$existingProfile = Database::selectOne("SELECT id FROM teacher_profiles WHERE user_id = ? LIMIT 1", [$userId]);
if ($existingProfile) {
Database::query(
"UPDATE teacher_profiles SET bio = ?, specialization = ? WHERE user_id = ?",
[$bio, $specialization, $userId]
);
} else {
Database::insert(
"INSERT INTO teacher_profiles (user_id, bio, specialization, revenue_share_pct, contract_type) VALUES (?, ?, ?, 50.00, 'exclusive')",
[$userId, $bio, $specialization]
);
}
$response->json([
'status' => 'success',
'message' => 'تم توثيق بيانات المعلم وإعداد كلمة المرور بنجاح!',
'data' => [
'full_name' => $fullName,
'specialization' => $specialization,
'grade_levels' => $gradeLevels
]
]);
}
/**
* Teacher Dashboard Statistics
* GET /api/teacher/dashboard
*/
public function getDashboard(Request $request, Response $response): void
{
$userId = $request->user_id;
// Total Courses
$coursesCount = (int)Database::selectOne("SELECT COUNT(*) as total FROM courses WHERE teacher_id = ?", [$userId])['total'];
// Total Lessons
$lessonsCount = (int)Database::selectOne(
"SELECT COUNT(l.id) as total FROM lessons l JOIN courses c ON l.course_id = c.id WHERE c.teacher_id = ?",
[$userId]
)['total'];
// Total Unique Active Students
$studentsCount = (int)Database::selectOne(
"SELECT COUNT(DISTINCT lp.user_id) as total FROM lesson_progress lp
JOIN lessons l ON lp.lesson_id = l.id
JOIN courses c ON l.course_id = c.id
WHERE c.teacher_id = ?",
[$userId]
)['total'];
$response->json([
'status' => 'success',
'data' => [
'courses_count' => $coursesCount,
'lessons_count' => $lessonsCount,
'students_count' => $studentsCount,
'rating' => 4.9,
'completion_avg' => 87.5
]
]);
}
/**
* List Teacher's Courses
* GET /api/teacher/courses
*/
public function getCourses(Request $request, Response $response): void
{
CurriculumService::ensureSchema();
$userId = (int)$request->user_id;
$courses = Database::select(
"SELECT c.id, c.uuid, c.title, c.description, c.semester, c.price_jod, c.is_published, c.created_at,
COUNT(l.id) as lessons_total
FROM courses c
LEFT JOIN lessons l ON l.course_id = c.id
WHERE c.teacher_id = ?
GROUP BY c.id
ORDER BY c.id ASC",
[$userId]
);
if (empty($courses)) {
// Auto-seed default courses for this teacher
$uuid1 = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));
$uuid2 = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff));
Database::query(
"INSERT INTO courses (uuid, teacher_id, subject_id, title, description, semester, price_jod, is_published)
VALUES (?, ?, 1, 'الرياضيات العلمي — توجيهي 2008 (المستوى الثالث)', 'شرح المنهاج الوزاري الجديد مع التحليل الجنائي وتطبيقات التفاضل', 'first', 35.00, 1),
(?, ?, 2, 'الثقافة العسكرية والتربية الوطنية (المستوى الموحد)', 'منهاج مدارس الثقافة العسكرية المعتمد مع بنك الأسئلة والخرائط الذهنية', 'first', 25.00, 1)",
[$uuid1, $userId, $uuid2, $userId]
);
$courses = Database::select(
"SELECT c.id, c.uuid, c.title, c.description, c.semester, c.price_jod, c.is_published, c.created_at,
COUNT(l.id) as lessons_total
FROM courses c
LEFT JOIN lessons l ON l.course_id = c.id
WHERE c.teacher_id = ?
GROUP BY c.id
ORDER BY c.id ASC",
[$userId]
);
}
$response->json([
'status' => 'success',
'data' => $courses
]);
}
/**
* Add New Course
* POST /api/teacher/courses
*/
public function addCourse(Request $request, Response $response): void
{
$body = $request->getBody();
$title = trim((string)($body['title'] ?? ''));
$description = trim((string)($body['description'] ?? ''));
$subjectId = (int)($body['subject_id'] ?? 1);
$semester = (string)($body['semester'] ?? 'first');
$price = (float)($body['price_jod'] ?? 35.00);
if (empty($title)) {
$response->status(400)->json([
'status' => 'error',
'message' => 'عنوان الدورة مطلوب'
]);
return;
}
$uuid = sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
$courseId = Database::insert(
"INSERT INTO courses (uuid, subject_id, teacher_id, title, description, semester, price_jod, is_published) VALUES (?, ?, ?, ?, ?, ?, ?, 1)",
[$uuid, $subjectId, $request->user_id, $title, $description, $semester, $price]
);
$response->status(201)->json([
'status' => 'success',
'message' => 'تم إنشاء الدورة بنجاح',
'data' => [
'course_id' => $courseId,
'uuid' => $uuid
]
]);
}
/**
* Add New Lesson to Course
* POST /api/teacher/lessons
*/
public function addLesson(Request $request, Response $response): void
{
$body = $request->getBody();
$courseId = (int)($body['course_id'] ?? 0);
$title = trim((string)($body['title'] ?? ''));
$bunnyVideoId = trim((string)($body['bunny_video_id'] ?? ''));
$duration = (int)($body['duration_seconds'] ?? 0);
$sequenceOrder = (int)($body['sequence_order'] ?? 1);
if (!$courseId || empty($title) || empty($bunnyVideoId)) {
$response->status(400)->json([
'status' => 'error',
'message' => 'معرف الدورة، عنوان الدرس، ومعرف فيديو Bunny مطلوبين'
]);
return;
}
// Verify Course Ownership
$course = Database::selectOne("SELECT id, teacher_id FROM courses WHERE id = ? LIMIT 1", [$courseId]);
if (!$course || ($course['teacher_id'] != $request->user_id && $request->role !== 'super_admin')) {
$response->status(403)->json([
'status' => 'error',
'message' => 'غير مصرح: لا تملك هذه الدورة'
]);
return;
}
$lessonId = Database::insert(
"INSERT INTO lessons (course_id, title, sequence_order, bunny_video_id, duration_seconds, is_free_preview) VALUES (?, ?, ?, ?, ?, 0)",
[$courseId, $title, $sequenceOrder, $bunnyVideoId, $duration]
);
$response->status(201)->json([
'status' => 'success',
'message' => 'تمت إضافة الدرس بنجاح',
'data' => [
'lesson_id' => $lessonId
]
]);
}
}