# session_manager.py import os from datetime import datetime from student_manager import StudentManager from curriculum_manager import CurriculumManager from level_test_manager import LevelTestManager from mastery_manager import MasteryManager from attention_manager import AttentionManager from device_identity_manager import DeviceIdentityManager try: from general_culture_manager import GeneralCultureManager except Exception: GeneralCultureManager = None try: from gap_plan_manager import GapPlanManager except Exception: GapPlanManager = None class SessionManager: def __init__(self): self.student_manager = StudentManager() self.curriculum_manager = CurriculumManager() self.level_test_manager = LevelTestManager() self.mastery_manager = MasteryManager() self.attention_manager = AttentionManager() self.device_manager = DeviceIdentityManager() self.general_culture_manager = None if GeneralCultureManager is not None: try: self.general_culture_manager = GeneralCultureManager() except Exception: self.general_culture_manager = None self.gap_plan_manager = None if GapPlanManager is not None: try: self.gap_plan_manager = GapPlanManager() except Exception: self.gap_plan_manager = None self.admin_password = os.getenv("ADMIN_PASSWORD", "1234") def now(self): return datetime.utcnow().isoformat() def normalize_identity(self, identity): try: return self.student_manager.normalize_identity(identity) except Exception: return str(identity or "").strip().lower().replace(" ", "_") def normalize_text(self, text): text = str(text or "").strip().lower() text = text.replace("أ", "ا").replace("إ", "ا").replace("آ", "ا") text = text.replace("ة", "ه") text = text.replace("ى", "ي") text = text.replace("ؤ", "و") text = text.replace("ئ", "ي") text = " ".join(text.split()) return text def normalize_grade(self, grade): try: return self.curriculum_manager.normalize_grade(grade) except Exception: return str(grade or "").strip() def get_student(self, identity): identity = self.normalize_identity(identity) try: student = self.student_manager.get_student(identity) if isinstance(student, dict): return student except Exception: pass return None def save_student(self, student): try: return self.student_manager.save_student(student) except Exception: return False def normalize_subject_key(self, subject): text = self.normalize_text(subject) if "رياض" in text or "math" in text or "ماث" in text: return "math", "رياضيات" if "عربي" in text or "arabic" in text: return "arabic", "لغة عربية" if "انجليزي" in text or "انكليزي" in text or "english" in text: return "english", "لغة إنجليزية" if "فيز" in text or "physics" in text: return "physics", "فيزياء" if "كيم" in text or "chemistry" in text: return "chemistry", "كيمياء" if "احياء" in text or "حيات" in text or "biology" in text: return "biology", "أحياء" if "ارض" in text or "جيولوج" in text or "earth" in text or "geology" in text: return "earth_science", "علوم الأرض" if "بيئ" in text or "environment" in text: return "environmental_science", "علوم بيئية" if ( "حاسوب" in text or "كمبيوتر" in text or "computer" in text or "ict" in text or "تكنولوجيا" in text or "رقمي" in text or "برمج" in text ): return "computer", "حاسوب" if "علوم" in text or "science" in text: return "science", "علوم" return text.replace(" ", "_") or "unknown", subject or "غير محدد" def is_level_test_subject(self, subject): key, name = self.normalize_subject_key(subject) level_subjects = { "math", "arabic", "english", "science", "computer", "physics", "chemistry", "biology", "earth_science", "environmental_science" } return key in level_subjects def decide_subject_route_safe(self, grade, subject): key, subject_name = self.normalize_subject_key(subject) if self.is_level_test_subject(subject): return { "route": "level_test", "subject_key": key, "subject_name": subject_name, "subject_type": "level_test", "needs_level_test": True, "grade": self.normalize_grade(grade), "message": "هذه مادة من مواد فحص المستوى." } return { "route": "general_culture", "subject_key": key, "subject_name": subject_name, "subject_type": "general_culture", "needs_level_test": False, "grade": self.normalize_grade(grade), "message": "هذه المادة ليست من مواد فحص المستوى." } def register_student_safe(self, student): identity = student.get("identity", "") try: result = self.student_manager.register_student(student) if isinstance(result, dict): return result except Exception: pass try: result = self.student_manager.register_student(**student) if isinstance(result, dict): return result except Exception: pass try: self.student_manager.save_student(student) except Exception: pass loaded = self.get_student(identity) if isinstance(loaded, dict): return loaded return student def build_new_student( self, student_name, email, grade, age, parent_password ): identity = self.normalize_identity(student_name) return { "identity": identity, "name": str(student_name or "").strip(), "email": str(email or "").strip(), "grade": str(grade or "").strip(), "age": str(age or "").strip(), "parent_password": str(parent_password or "").strip(), "created_at": self.now(), "updated_at": self.now(), "level_test": { "completed": False, "result": None }, "level_tests": {}, "homework": [], "flashcards": [], "quizzes": [], "reports": [], "lesson_history": [], "progress": {}, "skills": {}, "general_culture": {}, "authorized_devices": [] } def verify_student_login(self, student_name, hardware_fingerprint): return self.device_manager.verify_name_and_fingerprint( student_name=student_name, fingerprint=hardware_fingerprint ) def complete_new_student_after_verify( self, student_name, email, grade, age, parent_password, hardware_fingerprint ): student_name = str(student_name or "").strip() email = str(email or "").strip() grade = str(grade or "").strip() age = str(age or "").strip() parent_password = str(parent_password or "").strip() hardware_fingerprint = str(hardware_fingerprint or "").strip() if not student_name: return { "success": False, "message": "أدخل اسم الطالب.", "student": None, "next_step": "missing_name" } if not email: return { "success": False, "message": "أدخل البريد الإلكتروني.", "student": None, "next_step": "missing_email" } if not grade: return { "success": False, "message": "أدخل الصف.", "student": None, "next_step": "missing_grade" } if not parent_password: return { "success": False, "message": "أدخل كلمة مرور ولي الأمر.", "student": None, "next_step": "missing_parent_password" } if not hardware_fingerprint: return { "success": False, "message": "اضغط تحقق لأخذ البصمة.", "student": None, "next_step": "missing_fingerprint" } owner = self.device_manager.find_owner_by_fingerprint(hardware_fingerprint) if isinstance(owner, dict): return { "success": False, "message": "هذه البصمة مرتبطة بحساب آخر. لا يمكن استخدام جهاز واحد لحسابين.", "student": owner, "next_step": "blocked" } existing = self.device_manager.find_one_student_by_name(student_name) if isinstance(existing, dict): return { "success": False, "message": "الاسم موجود سابقًا. استخدم تحقق الجهاز الجديد بالبريد وكلمة مرور ولي الأمر.", "student": existing, "next_step": "verify_existing_device" } student = self.build_new_student( student_name=student_name, email=email, grade=grade, age=age, parent_password=parent_password ) student = self.register_student_safe(student) link_result = self.device_manager.link_device_to_student( identity=student.get("identity", self.normalize_identity(student_name)), fingerprint=hardware_fingerprint, label="الجهاز الأساسي" ) if not link_result.get("success"): return { "success": False, "message": link_result.get("message", "فشل ربط البصمة."), "student": student, "next_step": "device_error" } student = link_result.get("student", student) return { "success": True, "message": "تم إنشاء حساب الطالب وربط الجهاز. التالي: فحص المستوى.", "student": student, "next_step": "level_test" } def verify_existing_device( self, student_name, email, parent_password, hardware_fingerprint ): student_name = str(student_name or "").strip() email = str(email or "").strip() parent_password = str(parent_password or "").strip() hardware_fingerprint = str(hardware_fingerprint or "").strip() if not student_name or not email or not hardware_fingerprint: return { "success": False, "message": "أدخل الاسم والبريد واضغط تحقق لأخذ البصمة.", "student": None, "next_step": "missing_data" } student = self.device_manager.find_one_student_by_name(student_name) if not isinstance(student, dict): return { "success": False, "message": "لم يتم العثور على الطالب.", "student": None, "next_step": "not_found" } saved_email = str(student.get("email", "")).strip().lower() given_email = email.strip().lower() if saved_email and saved_email != given_email: return { "success": False, "message": "البريد الإلكتروني غير مطابق لملف الطالب.", "student": None, "next_step": "email_mismatch" } saved_parent_password = str(student.get("parent_password", "")).strip() if saved_parent_password: if str(parent_password) != saved_parent_password: return { "success": False, "message": "كلمة مرور ولي الأمر غير صحيحة.", "student": None, "next_step": "parent_password_mismatch" } else: if not parent_password: return { "success": False, "message": "أدخل كلمة مرور ولي الأمر لحفظها وربط الجهاز.", "student": None, "next_step": "missing_parent_password" } student["parent_password"] = parent_password self.save_student(student) owner = self.device_manager.find_owner_by_fingerprint(hardware_fingerprint) if isinstance(owner, dict): owner_identity = self.normalize_identity(owner.get("identity", "")) student_identity = self.normalize_identity(student.get("identity", "")) if owner_identity != student_identity: return { "success": False, "message": "هذه البصمة مرتبطة بحساب آخر. لا يمكن استخدام جهاز واحد لحسابين.", "student": owner, "next_step": "blocked" } link_result = self.device_manager.link_device_to_student( identity=student.get("identity", self.normalize_identity(student_name)), fingerprint=hardware_fingerprint, label="جهاز إضافي" ) if not link_result.get("success"): return { "success": False, "message": link_result.get("message", "فشل ربط الجهاز."), "student": None, "next_step": "device_error" } student = link_result.get("student", student) return { "success": True, "message": "تم توثيق الجهاز الجديد وربطه بحساب الطالب.", "student": student, "next_step": self.decide_next_step(student) } def subject_needs_level_test(self, student, subject): if not isinstance(student, dict): return False if not self.is_level_test_subject(subject): return False key, subject_name = self.normalize_subject_key(subject) level_tests = student.get("level_tests", {}) if isinstance(level_tests, dict): subject_result = level_tests.get(key) if isinstance(subject_result, dict) and subject_result.get("completed"): return False level_test = student.get("level_test", {}) if isinstance(level_test, dict): result = level_test.get("result", {}) if isinstance(result, dict): if result.get("subject_key") == key and level_test.get("completed"): return False return True def has_required_mastery_tasks(self, identity): try: return self.mastery_manager.has_required_mastery_tasks(identity) except Exception: return False def has_general_culture_tasks(self, identity): if self.general_culture_manager is None: return False try: return self.general_culture_manager.has_required_culture_tasks(identity) except Exception: return False def has_gap_plan_tasks(self, identity): if self.gap_plan_manager is None: return False try: tasks = self.gap_plan_manager.get_waiting_tasks(identity) return len(tasks) > 0 except Exception: return False def check_required_tasks(self, identity, subject=""): identity = self.normalize_identity(identity) student = self.get_student(identity) if not isinstance(student, dict): return { "allowed": False, "screen": "identity_required", "message": "لم يتم العثور على الطالب.", "tasks": [] } tasks = [] if subject and self.subject_needs_level_test(student, subject): tasks.append({ "type": "level_test", "title": "فحص المستوى", "message": "يجب إكمال فحص المستوى لهذه المادة أولًا." }) if self.has_required_mastery_tasks(identity): tasks.append({ "type": "mastery_badges", "title": "أوسمة الإتقان", "message": "يوجد أوسمة إتقان مطلوبة." }) if self.has_general_culture_tasks(identity): tasks.append({ "type": "general_culture", "title": "الثقافة العامة", "message": "يوجد أسئلة ثقافة عامة مطلوبة." }) if self.has_gap_plan_tasks(identity): tasks.append({ "type": "gap_plan", "title": "الخطة B", "message": "يوجد مهام من الخطة B." }) if tasks: return { "allowed": False, "screen": tasks[0]["type"], "message": tasks[0]["message"], "tasks": tasks } return { "allowed": True, "screen": "lesson", "message": "يمكن دخول الدرس.", "tasks": [] } def decide_next_step(self, student, subject="رياضيات"): if not isinstance(student, dict): return "identity_required" if not student.get("grade"): return "complete_profile" if self.subject_needs_level_test(student, subject): return "level_test" required = self.check_required_tasks( identity=student.get("identity", ""), subject=subject ) if not required.get("allowed"): return required.get("screen", "tasks") return "lesson" def start_student_session( self, identity="", name="", email="", grade="", age="", hardware_fingerprint="", device_source="hardware" ): student_name = name or identity or email verify = self.verify_student_login( student_name=student_name, hardware_fingerprint=hardware_fingerprint ) if verify.get("status") == "matched": student = verify.get("student") return { "success": True, "message": "تم الدخول من الاسم والبصمة.", "screen": "student_dashboard", "student": student, "next_step": self.decide_next_step(student) } if verify.get("status") == "new_student": return self.complete_new_student_after_verify( student_name=student_name, email=email, grade=grade, age=age, parent_password="", hardware_fingerprint=hardware_fingerprint ) return { "success": False, "message": verify.get("message", "لم يتم الدخول."), "screen": verify.get("status", "login_failed"), "student": verify.get("student") } def route_subject(self, identity, subject): identity = self.normalize_identity(identity) student = self.get_student(identity) if not isinstance(student, dict): return { "success": False, "screen": "identity_required", "message": "لم يتم العثور على الطالب.", "data": None } route = self.decide_subject_route_safe( grade=student.get("grade", ""), subject=subject ) if route.get("route") == "level_test": return { "success": True, "screen": "level_test", "message": route.get("message", "هذه مادة من مواد فحص المستوى."), "route": route, "data": None } return { "success": True, "screen": "general_culture", "message": route.get("message", "هذه المادة ليست من مواد فحص المستوى."), "route": route, "data": None } def create_level_test_for_subject(self, identity, subject): identity = self.normalize_identity(identity) student = self.get_student(identity) if not isinstance(student, dict): return { "success": False, "message": "لم يتم العثور على الطالب.", "test": None } if not self.is_level_test_subject(subject): return { "success": False, "message": "هذه المادة ليست من مواد فحص المستوى.", "test": None } key, subject_name = self.normalize_subject_key(subject) return self.level_test_manager.create_level_test( student=student, subject=subject_name ) def submit_level_test(self, identity, subject, test_data, answers_text): return self.level_test_manager.evaluate_level_test( identity=identity, subject=subject, test_data=test_data, answers_text=answers_text ) def admin_login(self, password): if str(password or "") == str(self.admin_password): return { "success": True, "message": "تم دخول الإدارة." } return { "success": False, "message": "كلمة مرور الإدارة غير صحيحة." } def student_status_summary(self, identity): identity = self.normalize_identity(identity) student = self.get_student(identity) if not isinstance(student, dict): return "لم يتم العثور على الطالب." devices = student.get("authorized_devices", []) if not isinstance(devices, list): devices = [] level_tests = student.get("level_tests", {}) if not isinstance(level_tests, dict): level_tests = {} text = f""" # حالة الطالب الاسم: {student.get("name", "")} البريد: {student.get("email", "")} الصف: {student.get("grade", "")} العمر: {student.get("age", "")} ## الأجهزة الموثقة عدد الأجهزة: {len(devices)} ## فحوصات المستوى المحفوظة """ if level_tests: for key, result in level_tests.items(): if isinstance(result, dict): text += f""" - {result.get("subject", key)}: {result.get("percentage", 0)}% - {result.get("level", "")} """ else: text += "\nلا توجد فحوصات مستوى محفوظة بعد." text += f""" ## التوجيه التالي {self.decide_next_step(student)} """ return text.strip()