You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
8.6 KiB
207 lines
8.6 KiB
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)
|