import datetime from django.utils import timezone from django.test import TestCase from unittest.mock import patch from django.core.files.uploadedfile import SimpleUploadedFile from dj_language.models import Language from apps.account.models import StudentUser, User, Notification from apps.course.models.course import Course, CourseCategory from apps.course.models.lesson import CourseChapter, CourseLesson, Lesson, LessonCompletion from apps.course.models.participant import Participant from apps.course.models.live_session import CourseLiveSession from apps.certificate.models import Certificate from apps.account.tasks import check_live_class_reminders_task, check_new_course_registration_task class NotificationFlowTests(TestCase): def setUp(self): # Create languages self.lang_fa, _ = Language.objects.update_or_create( code='fa', defaults={'name': 'Persian', 'status': True, 'countries': []} ) self.lang_en, _ = Language.objects.update_or_create( code='en', defaults={'name': 'English', 'status': True, 'countries': []} ) # Create category self.category = CourseCategory.objects.create( name=[{"title": "Category", "language_code": "en"}], slug=[{"title": "category", "language_code": "en"}] ) # Create student user self.student = StudentUser.objects.create( email='student_test@example.com', username='student_test', fullname='Test Student', language=self.lang_fa, # Persian template check fcm='token_student' ) # Create English student user for template check self.student_en = StudentUser.objects.create( email='student_en@example.com', username='student_en', fullname='Test Student EN', language=self.lang_en, fcm='token_student_en' ) def _create_course(self, slug, title_en, title_fa, status='ongoing'): thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg') return Course.objects.create( title=[ {"title": title_en, "language_code": "en"}, {"title": title_fa, "language_code": "fa"} ], slug=[{"title": slug, "language_code": "en"}], category=self.category, thumbnail=thumbnail, video_type=Course.VedioTypeChoices.YOUTUBE_LINK, video_link='https://example.com/video', is_online=False, level=Course.LevelChoices.BEGINNER, duration=10, lessons_count=0, description='Description', short_description='Short description', status=[ {"title": status, "language_code": "en"}, {"title": status, "language_code": "ru"} ], is_free=True, ) @patch('apps.account.notification_service.send_notification') def test_course_access_granted_notification(self, mock_send): # Event 1: Course Access Granted course = self._create_course('course-access', 'Course 1', 'دوره ۱') # Create participant (active=True by default) Participant.objects.create(student=self.student, course=course) # Verify notification created in DB (in Persian) notif_fa = Notification.objects.filter(user=self.student).first() self.assertIsNotNone(notif_fa) self.assertEqual(notif_fa.title, "دسترسی به دوره فعال شد") self.assertIn("دوره ۱", notif_fa.message) # Create participant for English student Participant.objects.create(student=self.student_en, course=course) notif_en = Notification.objects.filter(user=self.student_en).first() self.assertIsNotNone(notif_en) self.assertEqual(notif_en.title, "Course Access Granted") self.assertIn("Course 1", notif_en.message) # Verify send_notification was called self.assertTrue(mock_send.called) @patch('apps.account.notification_service.send_notification') def test_live_class_reminder_notification(self, mock_send): # Event 2: LIVE Class Reminder course = self._create_course('course-live', 'Course 2', 'دوره ۲') Participant.objects.create(student=self.student, course=course) # Create a live session starting in 2 hours session = CourseLiveSession.objects.create( course=course, subject='Live Lesson 1', started_at=timezone.now() + datetime.timedelta(hours=2), is_cancelled=False, reminder_sent=False ) # Run periodic task check_live_class_reminders_task() # Verify reminder sent session.refresh_from_db() self.assertTrue(session.reminder_sent) notif = Notification.objects.filter(user=self.student, title="یادآوری کلاس زنده").first() self.assertIsNotNone(notif) self.assertIn("دوره ۲", notif.message) # Test rescheduling resets reminder_sent session.started_at = timezone.now() + datetime.timedelta(hours=5) session.save() session.refresh_from_db() self.assertFalse(session.reminder_sent) @patch('apps.account.notification_service.send_notification') def test_course_completed_notification(self, mock_send): # Event 3: Course Completed course = self._create_course('course-complete', 'Course 3', 'دوره ۳') Participant.objects.create(student=self.student, course=course) chapter = CourseChapter.objects.create( course=course, title='Chapter 1', priority=1, is_active=True ) # Add 2 lessons l1 = Lesson.objects.create(title='Lesson 1', content_type='video_file', duration=5) cl1 = CourseLesson.objects.create(course=course, chapter=chapter, lesson=l1, priority=1, is_active=True) l2 = Lesson.objects.create(title='Lesson 2', content_type='video_file', duration=5) cl2 = CourseLesson.objects.create(course=course, chapter=chapter, lesson=l2, priority=2, is_active=True) # Complete first lesson LessonCompletion.objects.create(student=self.student, course_lesson=cl1) self.assertFalse(Notification.objects.filter(user=self.student, title="دوره به پایان رسید").exists()) # Complete second (last) lesson LessonCompletion.objects.create(student=self.student, course_lesson=cl2) # Verify notification triggered self.assertTrue(Notification.objects.filter(user=self.student, title="دوره به پایان رسید").exists()) @patch('apps.account.notification_service.send_notification') def test_certificate_issued_notification(self, mock_send): # Event 4: Certificate Issued course = self._create_course('course-cert', 'Course 4', 'دوره ۴') cert = Certificate.objects.create( student=self.student, course=course, status='pending' ) # Verify no notification yet self.assertFalse(Notification.objects.filter(user=self.student, title="گواهی صادر شد").exists()) # Approve certificate cert.status = 'approved' cert.save() # Verify notification triggered self.assertTrue(Notification.objects.filter(user=self.student, title="گواهی صادر شد").exists()) @patch('apps.account.notification_service.send_notification') def test_new_course_registration_notification(self, mock_send): # Event 5: New Course Registration student_recipient = User.objects.create( email='student_recipient@example.com', username='student_recipient', fullname='Recipient Student', user_type='student', is_active=True, language=self.lang_fa, fcm='token_recipient' ) course = self._create_course('course-new', 'New Course A', 'دوره جدید الف', status='registering') check_new_course_registration_task() course.refresh_from_db() self.assertTrue(course.notified_new_registration) notif = Notification.objects.filter(user=student_recipient, title="ثبت‌نام دوره جدید").first() self.assertIsNotNone(notif) self.assertIn("دوره جدید الف", notif.message)