Browse Source

notification fa language removed and runlanguage added

master
Mohsen Taba 1 week ago
parent
commit
0066c07de4
  1. 138
      apps/account/management/commands/seed_notification_templates.py
  2. 41
      apps/account/migrations/0008_remove_notificationtemplate_body_fa_and_more.py
  3. 8
      apps/account/models/notification.py
  4. 25
      apps/account/notification_service.py
  5. 4
      apps/account/tasks.py
  6. 22
      apps/account/tests/notifications/test_communication_notifications.py
  7. 24
      apps/account/tests/notifications/test_live_notifications.py
  8. 78
      apps/account/tests/notifications/test_notifications.py
  9. 24
      apps/account/tests/notifications/test_quiz_notifications.py
  10. 20
      apps/account/tests/notifications/test_retention_notifications.py
  11. 28
      apps/account/tests/notifications/test_transaction_notifications.py

138
apps/account/management/commands/seed_notification_templates.py

@ -2,153 +2,189 @@ from django.core.management.base import BaseCommand
from apps.account.models import NotificationTemplate from apps.account.models import NotificationTemplate
class Command(BaseCommand): class Command(BaseCommand):
help = 'Seeds default NotificationTemplate records in the database.'
help = 'Seeds default NotificationTemplate records in the database with RU and EN translations.'
def handle(self, *args, **options): def handle(self, *args, **options):
default_templates = [ default_templates = [
{ {
"notification_type": "course_access_granted", "notification_type": "course_access_granted",
"name": "دسترسی به دوره فعال شد",
"title_fa": "دسترسی به دوره فعال شد",
"name": "Доступ к курсу активирован",
"title_ru": "Доступ к курсу активирован",
"title_en": "Course Access Granted", "title_en": "Course Access Granted",
"body_fa": "دسترسی شما به دوره «{course_title}» فعال شد.",
"body_ru": "Ваш доступ к курсу «{course_title}» успешно активирован.",
"body_en": "Your access to the course '{course_title}' has been activated.", "body_en": "Your access to the course '{course_title}' has been activated.",
"placeholders_info": "{course_title}, {course_name}, {course_slug}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {course_slug}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "course_registered", "notification_type": "course_registered",
"name": "ثبت‌نام دوره جدید",
"title_fa": "ثبت‌نام دوره موفقیت‌آمیز بود",
"name": "Регистрация на курс",
"title_ru": "Успешная регистрация на курс",
"title_en": "Course Registration Successful", "title_en": "Course Registration Successful",
"body_fa": "ثبت‌نام شما در دوره «{course_title}» با موفقیت انجام شد.",
"body_ru": "Вы успешно зарегистрировались на курс «{course_title}».",
"body_en": "You have successfully registered for the course '{course_title}'.", "body_en": "You have successfully registered for the course '{course_title}'.",
"placeholders_info": "{course_title}, {course_name}, {course_slug}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {course_slug}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "lesson_completed", "notification_type": "lesson_completed",
"name": "اتمام درس",
"title_fa": "درس به اتمام رسید",
"name": "Урок завершен",
"title_ru": "Урок завершен",
"title_en": "Lesson Completed", "title_en": "Lesson Completed",
"body_fa": "تبریک! شما درس «{lesson_title}» را به پایان رساندید.",
"body_ru": "Поздравляем! Вы завершили изучение урока «{lesson_title}».",
"body_en": "Congratulations! You completed the lesson '{lesson_title}'.", "body_en": "Congratulations! You completed the lesson '{lesson_title}'.",
"placeholders_info": "{course_title}, {course_name}, {lesson_title}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {lesson_title}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "course_completed", "notification_type": "course_completed",
"name": "اتمام دوره",
"title_fa": "دوره به اتمام رسید",
"name": "Курс завершен",
"title_ru": "Курс завершен",
"title_en": "Course Completed", "title_en": "Course Completed",
"body_fa": "آفرین! شما دوره «{course_title}» را با موفقیت به پایان رساندید.",
"body_ru": "Отличная работа! Вы успешно завершили курс «{course_title}».",
"body_en": "Well done! You have completed the course '{course_title}'.", "body_en": "Well done! You have completed the course '{course_title}'.",
"placeholders_info": "{course_title}, {course_name}, {course_slug}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {course_slug}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "new_course_weekly", "notification_type": "new_course_weekly",
"name": "معرفی دوره جدید هفتگی",
"title_fa": "دوره جدید ثبت شد",
"name": "Новый курс за неделю",
"title_ru": "Добавлен новый курс",
"title_en": "New Course Registered", "title_en": "New Course Registered",
"body_fa": "دوره جدید «{course_title}» ثبت شده است. همین حالا می‌توانید ثبت‌نام کنید.",
"body_ru": "Зарегистрирован новый курс «{course_title}». Вы можете записаться прямо сейчас.",
"body_en": "A new course '{course_title}' has been registered. You can enroll now.", "body_en": "A new course '{course_title}' has been registered. You can enroll now.",
"placeholders_info": "{course_title}, {course_name}, {course_slug}" "placeholders_info": "{course_title}, {course_name}, {course_slug}"
}, },
{ {
"notification_type": "low_quiz_result", "notification_type": "low_quiz_result",
"name": "پیشنهاد شرکت مجدد در آزمون",
"title_fa": "پیشنهاد شرکت مجدد در آزمون",
"name": "Предложение пересдать тест",
"title_ru": "Предложение пересдать тест",
"title_en": "Quiz Retake Suggestion", "title_en": "Quiz Retake Suggestion",
"body_fa": "امتیاز شما در آزمون «{quiz_title}» کمتر از حد نصاب شده است. پیشنهاد می‌کنیم مجدداً در این آزمون شرکت کنید.",
"body_ru": "Вы набрали балл ниже проходного в тесте «{quiz_title}». Рекомендуем пройти его повторно.",
"body_en": "You scored below the passing threshold on quiz '{quiz_title}'. We suggest taking it again.", "body_en": "You scored below the passing threshold on quiz '{quiz_title}'. We suggest taking it again.",
"placeholders_info": "{quiz_title}, {student_name}, {fullname}" "placeholders_info": "{quiz_title}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "live_class_rescheduled", "notification_type": "live_class_rescheduled",
"name": "تغییر زمان کلاس زنده",
"title_fa": "زمان کلاس زنده تغییر کرد",
"name": "Время живого урока изменено",
"title_ru": "Время живого урока изменено",
"title_en": "Live Class Rescheduled", "title_en": "Live Class Rescheduled",
"body_fa": "زمان کلاس زنده برای دوره «{course_title}» تغییر یافته است.",
"body_ru": "Время проведения живого урока по курсу «{course_title}» было изменено.",
"body_en": "The live class for '{course_title}' has been rescheduled.", "body_en": "The live class for '{course_title}' has been rescheduled.",
"placeholders_info": "{course_title}, {course_name}, {session_subject}, {session_start_time}" "placeholders_info": "{course_title}, {course_name}, {session_subject}, {session_start_time}"
}, },
{ {
"notification_type": "live_class_cancelled", "notification_type": "live_class_cancelled",
"name": "لغو کلاس زنده",
"title_fa": "کلاس زنده لغو شد",
"name": "Живой урок отменен",
"title_ru": "Живой урок отменен",
"title_en": "Live Class Cancelled", "title_en": "Live Class Cancelled",
"body_fa": "کلاس زنده برای دوره «{course_title}» لغو شده است.",
"body_ru": "Живой урок по курсу «{course_title}» был отменен.",
"body_en": "The live class for '{course_title}' has been cancelled.", "body_en": "The live class for '{course_title}' has been cancelled.",
"placeholders_info": "{course_title}, {course_name}, {session_subject}" "placeholders_info": "{course_title}, {course_name}, {session_subject}"
}, },
{ {
"notification_type": "live_recording_available", "notification_type": "live_recording_available",
"name": "ویدئو ضبط شده کلاس آماده است",
"title_fa": "ویدئو ضبط شده کلاس آماده است",
"name": "Доступна запись живого урока",
"title_ru": "Доступна запись урока",
"title_en": "Live Recording Available", "title_en": "Live Recording Available",
"body_fa": "ویدئو ضبط شده کلاس زنده برای دوره «{course_title}» آماده مشاهده است.",
"body_ru": "Запись живого урока по курсу «{course_title}» уже доступна для просмотра.",
"body_en": "The recorded video of the live class for '{course_title}' is now available.", "body_en": "The recorded video of the live class for '{course_title}' is now available.",
"placeholders_info": "{course_title}, {course_name}" "placeholders_info": "{course_title}, {course_name}"
}, },
{ {
"notification_type": "missed_live_sessions", "notification_type": "missed_live_sessions",
"name": "غیبت متوالی کلاس زنده",
"title_fa": "غیبت متوالی در کلاس‌های زنده",
"name": "Пропуск живых уроков",
"title_ru": "Пропуск живых уроков",
"title_en": "Missed Live Sessions", "title_en": "Missed Live Sessions",
"body_fa": "شما ۲ جلسه زنده متوالی را در دوره «{course_title}» غایب بوده‌اید. توصیه می‌کنیم ویدئوهای ضبط شده را مشاهده کنید.",
"body_ru": "Вы пропустили 2 живых урока подряд по курсу «{course_title}». Рекомендуем посмотреть их в записи.",
"body_en": "You have missed 2 consecutive live sessions in the course '{course_title}'. We recommend watching the recordings.", "body_en": "You have missed 2 consecutive live sessions in the course '{course_title}'. We recommend watching the recordings.",
"placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "payment_successful", "notification_type": "payment_successful",
"name": "تراکنش موفق مالی",
"title_fa": "پرداخت موفقیت‌آمیز",
"name": "Оплата успешна",
"title_ru": "Оплата успешна",
"title_en": "Payment Successful", "title_en": "Payment Successful",
"body_fa": "پرداخت شما برای دوره «{course_title}» با موفقیت انجام شد.",
"body_ru": "Ваша оплата за курс «{course_title}» успешно проведена.",
"body_en": "Your payment for course '{course_title}' was successful.", "body_en": "Your payment for course '{course_title}' was successful.",
"placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "payment_failed", "notification_type": "payment_failed",
"name": "تراکنش ناموفق مالی",
"title_fa": "خطا در پرداخت",
"name": "Ошибка оплаты",
"title_ru": "Ошибка оплаты",
"title_en": "Payment Failed", "title_en": "Payment Failed",
"body_fa": "در پردازش پرداخت شما برای دوره «{course_title}» مشکلی رخ داد.",
"body_ru": "Произошла ошибка при обработке вашей оплаты за курс «{course_title}».",
"body_en": "We encountered an issue processing your payment for '{course_title}'.", "body_en": "We encountered an issue processing your payment for '{course_title}'.",
"placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "refund_completed", "notification_type": "refund_completed",
"name": "بازگشت وجه مالی",
"title_fa": "بازگشت وجه انجام شد",
"name": "Возврат средств",
"title_ru": "Возврат средств выполнен",
"title_en": "Refund Completed", "title_en": "Refund Completed",
"body_fa": "بازگشت وجه برای دوره «{course_title}» انجام شد.",
"body_ru": "Возврат средств за курс «{course_title}» успешно завершен.",
"body_en": "A refund has been successfully completed for the course '{course_title}'.", "body_en": "A refund has been successfully completed for the course '{course_title}'.",
"placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}" "placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}"
}, },
{ {
"notification_type": "student_inactivity", "notification_type": "student_inactivity",
"name": "عدم فعالیت کاربر",
"title_fa": "دلمان برایتان تنگ شده!",
"name": "Мы скучаем по вам",
"title_ru": "Мы скучаем по вам!",
"title_en": "We Miss You!", "title_en": "We Miss You!",
"body_fa": "در یک هفته گذشته هیچ درسی را مطالعه نکرده‌اید. منتظرتان هستیم تا مسیر یادگیری خود را ادامه دهید.",
"body_ru": "Вы не изучали уроки за последнюю неделю. Ждем вас для продолжения обучения!",
"body_en": "You haven't taken any lessons in the last week. Come back and continue your learning journey!", "body_en": "You haven't taken any lessons in the last week. Come back and continue your learning journey!",
"placeholders_info": "{student_name}, {fullname}" "placeholders_info": "{student_name}, {fullname}"
}, },
{ {
"notification_type": "teacher_reply", "notification_type": "teacher_reply",
"name": "پاسخ پیام استاد در چت",
"title_fa": "پاسخ جدید از استاد",
"name": "Ответ преподавателя",
"title_ru": "Новое сообщение от преподавателя",
"title_en": "New Message from Teacher", "title_en": "New Message from Teacher",
"body_fa": "استاد به پیام شما پاسخ داده است.",
"body_ru": "Преподаватель ответил на ваше сообщение.",
"body_en": "The teacher has replied to your message.", "body_en": "The teacher has replied to your message.",
"placeholders_info": "{student_name}, {fullname}" "placeholders_info": "{student_name}, {fullname}"
}, },
{
"notification_type": "teacher_reply_private",
"name": "Личное сообщение от преподавателя",
"title_ru": "Новое сообщение от преподавателя",
"title_en": "New Message from Teacher",
"body_ru": "Преподаватель ответил на ваше сообщение.",
"body_en": "The teacher has replied to your message.",
"placeholders_info": "{student_name}, {fullname}"
},
{
"notification_type": "teacher_reply_course",
"name": "Сообщение от преподавателя в чате курса",
"title_ru": "Сообщение от преподавателя в чате курса",
"title_en": "Teacher Post in Course Chat",
"body_ru": "Преподаватель опубликовал новое сообщение в чате курса.",
"body_en": "The teacher posted in the course chat.",
"placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}"
},
{ {
"notification_type": "support_reply", "notification_type": "support_reply",
"name": "پاسخ پیام پشتیبان در چت",
"title_fa": "پاسخ جدید از پشتیبان",
"name": "Ответ поддержки",
"title_ru": "Новое сообщение от поддержки",
"title_en": "New Message from Support", "title_en": "New Message from Support",
"body_fa": "پشتیبان به پیام شما پاسخ داده است.",
"body_ru": "Служба поддержки ответила на ваше сообщение.",
"body_en": "The support agent has replied to your message.", "body_en": "The support agent has replied to your message.",
"placeholders_info": "{student_name}, {fullname}" "placeholders_info": "{student_name}, {fullname}"
},
{
"notification_type": "certificate_issued",
"name": "Сертификат выдан",
"title_ru": "Сертификат выдан",
"title_en": "Certificate Issued",
"body_ru": "Ваш сертификат по курсу «{course_title}» успешно выпущен.",
"body_en": "Your certificate for the course '{course_title}' has been issued.",
"placeholders_info": "{course_title}, {course_name}, {student_name}, {fullname}"
},
{
"notification_type": "live_class_reminder",
"name": "Напоминание о живом уроке",
"title_ru": "Напоминание о живом уроке",
"title_en": "Live Class Reminder",
"body_ru": "Напоминаем, что живой урок «{session_subject}» начнется в {session_start_time}.",
"body_en": "Reminder: The live class '{session_subject}' will start at {session_start_time}.",
"placeholders_info": "{session_subject}, {session_start_time}, {student_name}, {fullname}"
} }
] ]
@ -158,9 +194,9 @@ class Command(BaseCommand):
notification_type=item['notification_type'], notification_type=item['notification_type'],
defaults={ defaults={
'name': item['name'], 'name': item['name'],
'title_fa': item['title_fa'],
'title_ru': item['title_ru'],
'title_en': item['title_en'], 'title_en': item['title_en'],
'body_fa': item['body_fa'],
'body_ru': item['body_ru'],
'body_en': item['body_en'], 'body_en': item['body_en'],
'placeholders_info': item['placeholders_info'], 'placeholders_info': item['placeholders_info'],
'is_active': True 'is_active': True

41
apps/account/migrations/0008_remove_notificationtemplate_body_fa_and_more.py

@ -0,0 +1,41 @@
# Generated by Django 4.2.30 on 2026-07-11 13:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0007_notificationtemplate_schedulednotification'),
]
operations = [
migrations.RemoveField(
model_name='notificationtemplate',
name='body_fa',
),
migrations.RemoveField(
model_name='notificationtemplate',
name='title_fa',
),
migrations.AddField(
model_name='notificationtemplate',
name='body_ru',
field=models.TextField(default='', max_length=1024, verbose_name='body (RU)'),
),
migrations.AddField(
model_name='notificationtemplate',
name='title_ru',
field=models.CharField(default='', max_length=255, verbose_name='title (RU)'),
),
migrations.AlterField(
model_name='notificationtemplate',
name='body_en',
field=models.TextField(default='', max_length=1024, verbose_name='body (EN)'),
),
migrations.AlterField(
model_name='notificationtemplate',
name='title_en',
field=models.CharField(default='', max_length=255, verbose_name='title (EN)'),
),
]

8
apps/account/models/notification.py

@ -36,10 +36,10 @@ class NotificationTemplate(models.Model):
name = models.CharField(max_length=100, verbose_name=_('name')) name = models.CharField(max_length=100, verbose_name=_('name'))
is_active = models.BooleanField(default=True, verbose_name=_('is active')) is_active = models.BooleanField(default=True, verbose_name=_('is active'))
title_fa = models.CharField(max_length=255, verbose_name=_('title (FA)'))
title_en = models.CharField(max_length=255, verbose_name=_('title (EN)'))
body_fa = models.TextField(max_length=1024, verbose_name=_('body (FA)'))
body_en = models.TextField(max_length=1024, verbose_name=_('body (EN)'))
title_ru = models.CharField(max_length=255, default="", verbose_name=_('title (RU)'))
title_en = models.CharField(max_length=255, default="", verbose_name=_('title (EN)'))
body_ru = models.TextField(max_length=1024, default="", verbose_name=_('body (RU)'))
body_en = models.TextField(max_length=1024, default="", verbose_name=_('body (EN)'))
placeholders_info = models.CharField(max_length=255, blank=True, null=True, verbose_name=_('allowed placeholders description')) placeholders_info = models.CharField(max_length=255, blank=True, null=True, verbose_name=_('allowed placeholders description'))

25
apps/account/notification_service.py

@ -149,7 +149,7 @@ def resolve_notification_route(notification_type, data):
return f"/course_info/quiz?slug={slug}" return f"/course_info/quiz?slug={slug}"
# Group 4: Chat Room path (/chat/chat_details?room_id=...) # Group 4: Chat Room path (/chat/chat_details?room_id=...)
elif notification_type in ['teacher_reply', 'support_reply']:
elif notification_type in ['teacher_reply', 'teacher_reply_private', 'teacher_reply_course', 'support_reply']:
room_id = data.get('room_id') room_id = data.get('room_id')
if room_id: if room_id:
return f"/chat/chat_details?room_id={room_id}" return f"/chat/chat_details?room_id={room_id}"
@ -167,13 +167,18 @@ def resolve_notification_route(notification_type, data):
return None return None
def create_and_send_notification(user, title_en, body_en, title_fa, body_fa, service='imam-javad',
data=None, notification_type=None, action='navigate', navigate_to=None):
def create_and_send_notification(user, title_en, body_en, title_fa=None, body_fa=None, service='imam-javad',
data=None, notification_type=None, action='navigate', navigate_to=None,
title_ru=None, body_ru=None):
""" """
Creates a Notification record in the database and sends a push notification to FCM. Creates a Notification record in the database and sends a push notification to FCM.
Loads and renders the NotificationTemplate from the database if present. Loads and renders the NotificationTemplate from the database if present.
If the template is inactive, the notification is discarded. If the template is inactive, the notification is discarded.
""" """
# Map Persian arguments to Russian to preserve backward compatibility with existing signals/tasks
title_ru = title_ru or title_fa
body_ru = body_ru or body_fa
# Auto-resolve notification type from data payload if not provided # Auto-resolve notification type from data payload if not provided
if not notification_type and isinstance(data, dict): if not notification_type and isinstance(data, dict):
notification_type = data.get('type') notification_type = data.get('type')
@ -186,9 +191,9 @@ def create_and_send_notification(user, title_en, body_en, title_fa, body_fa, ser
logger.info(f"Notification type '{notification_type}' is disabled via database template settings.") logger.info(f"Notification type '{notification_type}' is disabled via database template settings.")
return None return None
# Override templates with database values # Override templates with database values
title_fa = template.title_fa
title_ru = template.title_ru
title_en = template.title_en title_en = template.title_en
body_fa = template.body_fa
body_ru = template.body_ru
body_en = template.body_en body_en = template.body_en
# 2. Render templates safely with dynamic context # 2. Render templates safely with dynamic context
@ -196,19 +201,19 @@ def create_and_send_notification(user, title_en, body_en, title_fa, body_fa, ser
safe_ctx = SafeDict(context) safe_ctx = SafeDict(context)
try: try:
title_fa = title_fa.format(**safe_ctx) if title_fa else ""
title_ru = title_ru.format(**safe_ctx) if title_ru else ""
title_en = title_en.format(**safe_ctx) if title_en else "" title_en = title_en.format(**safe_ctx) if title_en else ""
body_fa = body_fa.format(**safe_ctx) if body_fa else ""
body_ru = body_ru.format(**safe_ctx) if body_ru else ""
body_en = body_en.format(**safe_ctx) if body_en else "" body_en = body_en.format(**safe_ctx) if body_en else ""
except Exception as e: except Exception as e:
logger.error(f"Error formatting templates: {e}") logger.error(f"Error formatting templates: {e}")
# Determine user localized text # Determine user localized text
lang = getattr(user, 'language', None) lang = getattr(user, 'language', None)
lang_code = lang.code if lang and hasattr(lang, 'code') else 'fa'
lang_code = lang.code if lang and hasattr(lang, 'code') else 'ru'
title = title_fa if lang_code == 'fa' else title_en
message = body_fa if lang_code == 'fa' else body_en
title = title_ru if lang_code == 'ru' else title_en
message = body_ru if lang_code == 'ru' else body_en
# Auto-resolve GoRouter navigation route if not provided # Auto-resolve GoRouter navigation route if not provided
if not navigate_to and notification_type: if not navigate_to and notification_type:

4
apps/account/tasks.py

@ -437,8 +437,8 @@ def run_scheduled_notification_task(campaign_id):
user=user, user=user,
title_en=template.title_en, title_en=template.title_en,
body_en=template.body_en, body_en=template.body_en,
title_fa=template.title_fa,
body_fa=template.body_fa,
title_ru=template.title_ru,
body_ru=template.body_ru,
service='imam-javad', service='imam-javad',
data={'type': template.notification_type}, data={'type': template.notification_type},
notification_type=template.notification_type notification_type=template.notification_type

22
apps/account/tests/notifications/test_communication_notifications.py

@ -13,9 +13,9 @@ from apps.chat.models import RoomMessage, ChatMessage
class CommunicationNotificationsFlowTests(TestCase): class CommunicationNotificationsFlowTests(TestCase):
def setUp(self): def setUp(self):
# Create languages # Create languages
self.lang_fa, _ = Language.objects.update_or_create(
code='fa',
defaults={'name': 'Persian', 'status': True, 'countries': []}
self.lang_ru, _ = Language.objects.update_or_create(
code='ru',
defaults={'name': 'Russian', 'status': True, 'countries': []}
) )
self.lang_en, _ = Language.objects.update_or_create( self.lang_en, _ = Language.objects.update_or_create(
code='en', code='en',
@ -33,7 +33,7 @@ class CommunicationNotificationsFlowTests(TestCase):
email='student_comm@example.com', email='student_comm@example.com',
username='student_comm', username='student_comm',
fullname='Comm Student', fullname='Comm Student',
language=self.lang_fa,
language=self.lang_ru,
fcm='token_comm_student' fcm='token_comm_student'
) )
@ -44,7 +44,7 @@ class CommunicationNotificationsFlowTests(TestCase):
fullname='Teacher Comm', fullname='Teacher Comm',
user_type='professor', user_type='professor',
is_active=True, is_active=True,
language=self.lang_fa
language=self.lang_ru
) )
# Create support user (admin) # Create support user (admin)
@ -54,7 +54,7 @@ class CommunicationNotificationsFlowTests(TestCase):
fullname='Support Comm', fullname='Support Comm',
user_type='admin', user_type='admin',
is_active=True, is_active=True,
language=self.lang_fa
language=self.lang_ru
) )
# Create Course # Create Course
@ -62,7 +62,7 @@ class CommunicationNotificationsFlowTests(TestCase):
self.course = Course.objects.create( self.course = Course.objects.create(
title=[ title=[
{"title": "Course 1", "language_code": "en"}, {"title": "Course 1", "language_code": "en"},
{"title": "دوره ۱", "language_code": "fa"}
{"title": "Курс 1", "language_code": "ru"}
], ],
slug=[{"title": "course-1", "language_code": "en"}], slug=[{"title": "course-1", "language_code": "en"}],
category=self.category, category=self.category,
@ -105,7 +105,7 @@ class CommunicationNotificationsFlowTests(TestCase):
) )
# Verify notification sent to the student # Verify notification sent to the student
notif = Notification.objects.filter(user=self.student, title="پیام جدید از طرف استاد").first()
notif = Notification.objects.filter(user=self.student, title="Новое сообщение от преподавателя").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("Hello from teacher", notif.message) self.assertIn("Hello from teacher", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@ -129,7 +129,7 @@ class CommunicationNotificationsFlowTests(TestCase):
) )
# Verify notification sent to the student # Verify notification sent to the student
notif = Notification.objects.filter(user=self.student, title="پاسخ پشتیبانی").first()
notif = Notification.objects.filter(user=self.student, title="Новое сообщение от поддержки").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("How can I help you?", notif.message) self.assertIn("How can I help you?", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@ -153,10 +153,10 @@ class CommunicationNotificationsFlowTests(TestCase):
) )
# Verify notification sent to the student enrolled # Verify notification sent to the student enrolled
notif = Notification.objects.filter(user=self.student, title="پیام استاد در گفتگوی دوره").first()
notif = Notification.objects.filter(user=self.student, title="Сообщение от преподавателя в чате курса").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("homework", notif.message) self.assertIn("homework", notif.message)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')

24
apps/account/tests/notifications/test_live_notifications.py

@ -13,9 +13,9 @@ from apps.course.models.live_session import CourseLiveSession, LiveSessionRecord
class LiveNotificationsFlowTests(TestCase): class LiveNotificationsFlowTests(TestCase):
def setUp(self): def setUp(self):
# Create languages # Create languages
self.lang_fa, _ = Language.objects.update_or_create(
code='fa',
defaults={'name': 'Persian', 'status': True, 'countries': []}
self.lang_ru, _ = Language.objects.update_or_create(
code='ru',
defaults={'name': 'Russian', 'status': True, 'countries': []}
) )
self.lang_en, _ = Language.objects.update_or_create( self.lang_en, _ = Language.objects.update_or_create(
code='en', code='en',
@ -33,7 +33,7 @@ class LiveNotificationsFlowTests(TestCase):
email='student_live@example.com', email='student_live@example.com',
username='student_live', username='student_live',
fullname='Live Student', fullname='Live Student',
language=self.lang_fa,
language=self.lang_ru,
fcm='token_live_student' fcm='token_live_student'
) )
@ -42,7 +42,7 @@ class LiveNotificationsFlowTests(TestCase):
self.course = Course.objects.create( self.course = Course.objects.create(
title=[ title=[
{"title": "Course 1", "language_code": "en"}, {"title": "Course 1", "language_code": "en"},
{"title": "دوره ۱", "language_code": "fa"}
{"title": "Курс 1", "language_code": "ru"}
], ],
slug=[{"title": "course-1", "language_code": "en"}], slug=[{"title": "course-1", "language_code": "en"}],
category=self.category, category=self.category,
@ -81,11 +81,11 @@ class LiveNotificationsFlowTests(TestCase):
self.session.is_cancelled = True self.session.is_cancelled = True
self.session.save() self.session.save()
# Check DB notification for Persian student
notif = Notification.objects.filter(user=self.student, title="کلاس زنده لغو شد").first()
# Check DB notification for Russian student
notif = Notification.objects.filter(user=self.student, title="Живой урок отменен").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("Lesson One Live", notif.message) self.assertIn("Lesson One Live", notif.message)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -98,10 +98,10 @@ class LiveNotificationsFlowTests(TestCase):
self.session.save() self.session.save()
# Check DB notification # Check DB notification
notif = Notification.objects.filter(user=self.student, title="کلاس زنده تغییر زمان یافت").first()
notif = Notification.objects.filter(user=self.student, title="Время живого урока изменено").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("Lesson One Live", notif.message) self.assertIn("Lesson One Live", notif.message)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -115,8 +115,8 @@ class LiveNotificationsFlowTests(TestCase):
) )
# Check DB notification # Check DB notification
notif = Notification.objects.filter(user=self.student, title="ضبط کلاس زنده در دسترس است").first()
notif = Notification.objects.filter(user=self.student, title="Доступна запись урока").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("Lesson One Live", notif.message) self.assertIn("Lesson One Live", notif.message)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)

78
apps/account/tests/notifications/test_notifications.py

@ -16,9 +16,9 @@ from apps.account.tasks import check_live_class_reminders_task, check_new_course
class NotificationFlowTests(TestCase): class NotificationFlowTests(TestCase):
def setUp(self): def setUp(self):
# Create languages # Create languages
self.lang_fa, _ = Language.objects.update_or_create(
code='fa',
defaults={'name': 'Persian', 'status': True, 'countries': []}
self.lang_ru, _ = Language.objects.update_or_create(
code='ru',
defaults={'name': 'Russian', 'status': True, 'countries': []}
) )
self.lang_en, _ = Language.objects.update_or_create( self.lang_en, _ = Language.objects.update_or_create(
code='en', code='en',
@ -36,7 +36,7 @@ class NotificationFlowTests(TestCase):
email='student_test@example.com', email='student_test@example.com',
username='student_test', username='student_test',
fullname='Test Student', fullname='Test Student',
language=self.lang_fa, # Persian template check
language=self.lang_ru, # Russian template check
fcm='token_student' fcm='token_student'
) )
@ -49,12 +49,12 @@ class NotificationFlowTests(TestCase):
fcm='token_student_en' fcm='token_student_en'
) )
def _create_course(self, slug, title_en, title_fa, status='ongoing'):
def _create_course(self, slug, title_en, title_ru, status='ongoing'):
thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg') thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg')
return Course.objects.create( return Course.objects.create(
title=[ title=[
{"title": title_en, "language_code": "en"}, {"title": title_en, "language_code": "en"},
{"title": title_fa, "language_code": "fa"}
{"title": title_ru, "language_code": "ru"}
], ],
slug=[{"title": slug, "language_code": "en"}], slug=[{"title": slug, "language_code": "en"}],
category=self.category, category=self.category,
@ -77,19 +77,19 @@ class NotificationFlowTests(TestCase):
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
def test_course_access_granted_notification(self, mock_send): def test_course_access_granted_notification(self, mock_send):
# Event 1: Course Access Granted # Event 1: Course Access Granted
course = self._create_course('course-access', 'Course 1', 'دوره ۱')
course = self._create_course('course-access', 'Course 1', 'Курс 1')
# Create participant (active=True by default) # Create participant (active=True by default)
Participant.objects.create(student=self.student, course=course) 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)
self.assertEqual(notif_fa.notification_type, "course_access_granted")
self.assertEqual(notif_fa.action, "navigate")
self.assertEqual(notif_fa.navigate_to, "/course_info?slug=course-access")
# Verify notification created in DB (in Russian)
notif_ru = Notification.objects.filter(user=self.student).first()
self.assertIsNotNone(notif_ru)
self.assertEqual(notif_ru.title, "Доступ к курсу активирован")
self.assertIn("Курс 1", notif_ru.message)
self.assertEqual(notif_ru.notification_type, "course_access_granted")
self.assertEqual(notif_ru.action, "navigate")
self.assertEqual(notif_ru.navigate_to, "/course_info?slug=course-access")
# Create participant for English student # Create participant for English student
Participant.objects.create(student=self.student_en, course=course) Participant.objects.create(student=self.student_en, course=course)
@ -113,7 +113,7 @@ class NotificationFlowTests(TestCase):
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
def test_live_class_reminder_notification(self, mock_send): def test_live_class_reminder_notification(self, mock_send):
# Event 2: LIVE Class Reminder # Event 2: LIVE Class Reminder
course = self._create_course('course-live', 'Course 2', 'دوره ۲')
course = self._create_course('course-live', 'Course 2', 'Курс 2')
Participant.objects.create(student=self.student, course=course) Participant.objects.create(student=self.student, course=course)
# Create a live session starting in 2 hours # Create a live session starting in 2 hours
@ -132,9 +132,9 @@ class NotificationFlowTests(TestCase):
session.refresh_from_db() session.refresh_from_db()
self.assertTrue(session.reminder_sent) self.assertTrue(session.reminder_sent)
notif = Notification.objects.filter(user=self.student, title="یادآوری کلاس زنده").first()
notif = Notification.objects.filter(user=self.student, title="Напоминание о живом уроке").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("دوره ۲", notif.message)
self.assertIn("Live Lesson 1", notif.message)
# Test rescheduling resets reminder_sent # Test rescheduling resets reminder_sent
session.started_at = timezone.now() + datetime.timedelta(hours=5) session.started_at = timezone.now() + datetime.timedelta(hours=5)
@ -146,7 +146,7 @@ class NotificationFlowTests(TestCase):
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
def test_course_completed_notification(self, mock_send): def test_course_completed_notification(self, mock_send):
# Event 3: Course Completed # Event 3: Course Completed
course = self._create_course('course-complete', 'Course 3', 'دوره ۳')
course = self._create_course('course-complete', 'Course 3', 'Курс 3')
Participant.objects.create(student=self.student, course=course) Participant.objects.create(student=self.student, course=course)
chapter = CourseChapter.objects.create( chapter = CourseChapter.objects.create(
@ -165,18 +165,18 @@ class NotificationFlowTests(TestCase):
# Complete first lesson # Complete first lesson
LessonCompletion.objects.create(student=self.student, course_lesson=cl1) LessonCompletion.objects.create(student=self.student, course_lesson=cl1)
self.assertFalse(Notification.objects.filter(user=self.student, title="دوره به پایان رسید").exists())
self.assertFalse(Notification.objects.filter(user=self.student, title="Курс завершен").exists())
# Complete second (last) lesson # Complete second (last) lesson
LessonCompletion.objects.create(student=self.student, course_lesson=cl2) LessonCompletion.objects.create(student=self.student, course_lesson=cl2)
# Verify notification triggered # Verify notification triggered
self.assertTrue(Notification.objects.filter(user=self.student, title="دوره به پایان رسید").exists())
self.assertTrue(Notification.objects.filter(user=self.student, title="Курс завершен").exists())
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
def test_certificate_issued_notification(self, mock_send): def test_certificate_issued_notification(self, mock_send):
# Event 4: Certificate Issued # Event 4: Certificate Issued
course = self._create_course('course-cert', 'Course 4', 'دوره ۴')
course = self._create_course('course-cert', 'Course 4', 'Курс 4')
cert = Certificate.objects.create( cert = Certificate.objects.create(
student=self.student, student=self.student,
@ -185,14 +185,14 @@ class NotificationFlowTests(TestCase):
) )
# Verify no notification yet # Verify no notification yet
self.assertFalse(Notification.objects.filter(user=self.student, title="گواهی صادر شد").exists())
self.assertFalse(Notification.objects.filter(user=self.student, title="Сертификат выдан").exists())
# Approve certificate # Approve certificate
cert.status = 'approved' cert.status = 'approved'
cert.save() cert.save()
# Verify notification triggered # Verify notification triggered
self.assertTrue(Notification.objects.filter(user=self.student, title="گواهی صادر شد").exists())
self.assertTrue(Notification.objects.filter(user=self.student, title="Сертификат выдан").exists())
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
def test_new_course_registration_notification(self, mock_send): def test_new_course_registration_notification(self, mock_send):
@ -203,20 +203,20 @@ class NotificationFlowTests(TestCase):
fullname='Recipient Student', fullname='Recipient Student',
user_type='student', user_type='student',
is_active=True, is_active=True,
language=self.lang_fa,
language=self.lang_ru,
fcm='token_recipient' fcm='token_recipient'
) )
course = self._create_course('course-new', 'New Course A', 'دوره جدید الف', status='registering')
course = self._create_course('course-new', 'New Course A', 'Новый курс А', status='registering')
check_new_course_registration_task() check_new_course_registration_task()
course.refresh_from_db() course.refresh_from_db()
self.assertTrue(course.notified_new_registration) self.assertTrue(course.notified_new_registration)
notif = Notification.objects.filter(user=student_recipient, title="ثبت‌نام دوره جدید").first()
notif = Notification.objects.filter(user=student_recipient, title="Добавлен новый курс").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("دوره جدید الف", notif.message)
self.assertIn("Новый курс А", notif.message)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
def test_notification_template_customization_and_deactivation(self, mock_send): def test_notification_template_customization_and_deactivation(self, mock_send):
@ -225,14 +225,14 @@ class NotificationFlowTests(TestCase):
template = NotificationTemplate.objects.create( template = NotificationTemplate.objects.create(
notification_type="custom_test_type", notification_type="custom_test_type",
name="Test Template", name="Test Template",
title_fa="سلام {student_name} به دوره {course_title}",
title_ru="Привет {student_name} к курсу {course_title}",
title_en="Hello {student_name} to course {course_title}", title_en="Hello {student_name} to course {course_title}",
body_fa="توضیحات فارسی {student_name}",
body_ru="Русское описание {student_name}",
body_en="English description {student_name}", body_en="English description {student_name}",
is_active=True is_active=True
) )
course = self._create_course('test-tpl-course', 'Tpl Course', 'دوره تی‌پی‌ال')
course = self._create_course('test-tpl-course', 'Tpl Course', 'Курс Шаблон')
# 2. Trigger notification and verify custom text formatting # 2. Trigger notification and verify custom text formatting
from apps.account.notification_service import create_and_send_notification from apps.account.notification_service import create_and_send_notification
@ -240,8 +240,8 @@ class NotificationFlowTests(TestCase):
user=self.student, user=self.student,
title_en="Default Title EN", title_en="Default Title EN",
body_en="Default Body EN", body_en="Default Body EN",
title_fa="Default Title FA",
body_fa="Default Body FA",
title_ru="Default Title RU",
body_ru="Default Body RU",
service='imam-javad', service='imam-javad',
data={'type': 'custom_test_type', 'course_id': course.id} data={'type': 'custom_test_type', 'course_id': course.id}
) )
@ -249,8 +249,8 @@ class NotificationFlowTests(TestCase):
notif = Notification.objects.filter(user=self.student).order_by('-id').first() notif = Notification.objects.filter(user=self.student).order_by('-id').first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
# Verify it loaded from template and formatted using course name & student name # Verify it loaded from template and formatted using course name & student name
self.assertEqual(notif.title, f"سلام {self.student.fullname} به دوره دوره تی‌پی‌ال")
self.assertEqual(notif.message, f"توضیحات فارسی {self.student.fullname}")
self.assertEqual(notif.title, f"Привет {self.student.fullname} к курсу Курс Шаблон")
self.assertEqual(notif.message, f"Русское описание {self.student.fullname}")
# 3. Disable template and verify notification is discarded # 3. Disable template and verify notification is discarded
template.is_active = False template.is_active = False
@ -261,8 +261,8 @@ class NotificationFlowTests(TestCase):
user=self.student, user=self.student,
title_en="Default Title EN", title_en="Default Title EN",
body_en="Default Body EN", body_en="Default Body EN",
title_fa="Default Title FA",
body_fa="Default Body FA",
title_ru="Default Title RU",
body_ru="Default Body RU",
service='imam-javad', service='imam-javad',
data={'type': 'custom_test_type', 'course_id': course.id} data={'type': 'custom_test_type', 'course_id': course.id}
) )
@ -277,9 +277,9 @@ class NotificationFlowTests(TestCase):
template = NotificationTemplate.objects.create( template = NotificationTemplate.objects.create(
notification_type="sched_test", notification_type="sched_test",
name="Scheduled Test", name="Scheduled Test",
title_fa="تست زمان‌بندی",
title_ru="Тест планирования",
title_en="Scheduled Test", title_en="Scheduled Test",
body_fa="تست",
body_ru="Тест",
body_en="Test" body_en="Test"
) )

24
apps/account/tests/notifications/test_quiz_notifications.py

@ -13,9 +13,9 @@ from apps.account.tasks import check_low_quiz_results_task
class QuizNotificationFlowTests(TestCase): class QuizNotificationFlowTests(TestCase):
def setUp(self): def setUp(self):
# Create languages # Create languages
self.lang_fa, _ = Language.objects.update_or_create(
code='fa',
defaults={'name': 'Persian', 'status': True, 'countries': []}
self.lang_ru, _ = Language.objects.update_or_create(
code='ru',
defaults={'name': 'Russian', 'status': True, 'countries': []}
) )
self.lang_en, _ = Language.objects.update_or_create( self.lang_en, _ = Language.objects.update_or_create(
code='en', code='en',
@ -33,7 +33,7 @@ class QuizNotificationFlowTests(TestCase):
email='student_quiz@example.com', email='student_quiz@example.com',
username='student_quiz', username='student_quiz',
fullname='Quiz Student', fullname='Quiz Student',
language=self.lang_fa,
language=self.lang_ru,
fcm='token_quiz_student' fcm='token_quiz_student'
) )
@ -42,7 +42,7 @@ class QuizNotificationFlowTests(TestCase):
self.course = Course.objects.create( self.course = Course.objects.create(
title=[ title=[
{"title": "Course 1", "language_code": "en"}, {"title": "Course 1", "language_code": "en"},
{"title": "دوره ۱", "language_code": "fa"}
{"title": "Курс 1", "language_code": "ru"}
], ],
slug=[{"title": "course-1", "language_code": "en"}], slug=[{"title": "course-1", "language_code": "en"}],
category=self.category, category=self.category,
@ -64,7 +64,7 @@ class QuizNotificationFlowTests(TestCase):
course=self.course, course=self.course,
title=[ title=[
{"title": "Quiz A", "language_code": "en"}, {"title": "Quiz A", "language_code": "en"},
{"title": "آزمون الف", "language_code": "fa"}
{"title": "Тест А", "language_code": "ru"}
], ],
each_question_timing=60, each_question_timing=60,
status=True status=True
@ -88,10 +88,10 @@ class QuizNotificationFlowTests(TestCase):
# Run periodic task # Run periodic task
check_low_quiz_results_task() check_low_quiz_results_task()
# Verify reminder sent to the student (Persian template check)
notif = Notification.objects.filter(user=self.student, title="پیشنهاد شرکت مجدد در آزمون").first()
# Verify reminder sent to the student (Russian template check)
notif = Notification.objects.filter(user=self.student, title="Предложение пересдать тест").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("آزمون الف", notif.message)
self.assertIn("Тест А", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -110,7 +110,7 @@ class QuizNotificationFlowTests(TestCase):
check_low_quiz_results_task() check_low_quiz_results_task()
self.assertFalse(Notification.objects.filter(user=self.student, title="پیشنهاد شرکت مجدد در آزمون").exists())
self.assertFalse(Notification.objects.filter(user=self.student, title="Предложение пересдать тест").exists())
self.assertFalse(mock_send.called) self.assertFalse(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -142,7 +142,7 @@ class QuizNotificationFlowTests(TestCase):
check_low_quiz_results_task() check_low_quiz_results_task()
# Should not suggest retake since they passed subsequently # Should not suggest retake since they passed subsequently
self.assertFalse(Notification.objects.filter(user=self.student, title="پیشنهاد شرکت مجدد در آزمون").exists())
self.assertFalse(Notification.objects.filter(user=self.student, title="Предложение пересдать тест").exists())
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
def test_no_reminder_if_already_retaken_even_if_failed(self, mock_send): def test_no_reminder_if_already_retaken_even_if_failed(self, mock_send):
@ -173,4 +173,4 @@ class QuizNotificationFlowTests(TestCase):
check_low_quiz_results_task() check_low_quiz_results_task()
self.assertFalse(Notification.objects.filter(user=self.student, title="پیشنهاد شرکت مجدد در آزمون").exists())
self.assertFalse(Notification.objects.filter(user=self.student, title="Предложение пересдать тест").exists())

20
apps/account/tests/notifications/test_retention_notifications.py

@ -15,9 +15,9 @@ from apps.account.tasks import check_inactive_students_task
class RetentionNotificationsFlowTests(TestCase): class RetentionNotificationsFlowTests(TestCase):
def setUp(self): def setUp(self):
# Create languages # Create languages
self.lang_fa, _ = Language.objects.update_or_create(
code='fa',
defaults={'name': 'Persian', 'status': True, 'countries': []}
self.lang_ru, _ = Language.objects.update_or_create(
code='ru',
defaults={'name': 'Russian', 'status': True, 'countries': []}
) )
self.lang_en, _ = Language.objects.update_or_create( self.lang_en, _ = Language.objects.update_or_create(
code='en', code='en',
@ -35,7 +35,7 @@ class RetentionNotificationsFlowTests(TestCase):
email='student_ret@example.com', email='student_ret@example.com',
username='student_ret', username='student_ret',
fullname='Ret Student', fullname='Ret Student',
language=self.lang_fa,
language=self.lang_ru,
fcm='token_ret_student' fcm='token_ret_student'
) )
@ -44,7 +44,7 @@ class RetentionNotificationsFlowTests(TestCase):
self.course = Course.objects.create( self.course = Course.objects.create(
title=[ title=[
{"title": "Course 1", "language_code": "en"}, {"title": "Course 1", "language_code": "en"},
{"title": "دوره ۱", "language_code": "fa"}
{"title": "Курс 1", "language_code": "ru"}
], ],
slug=[{"title": "course-1", "language_code": "en"}], slug=[{"title": "course-1", "language_code": "en"}],
category=self.category, category=self.category,
@ -80,7 +80,7 @@ class RetentionNotificationsFlowTests(TestCase):
check_inactive_students_task() check_inactive_students_task()
# Check DB notification # Check DB notification
notif = Notification.objects.filter(user=self.student, title="دلمان برایتان تنگ شده!").first()
notif = Notification.objects.filter(user=self.student, title="Мы скучаем по вам!").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@ -93,7 +93,7 @@ class RetentionNotificationsFlowTests(TestCase):
check_inactive_students_task() check_inactive_students_task()
self.assertFalse(Notification.objects.filter(user=self.student, title="دلمان برایتان تنگ شده!").exists())
self.assertFalse(Notification.objects.filter(user=self.student, title="Мы скучаем по вам!").exists())
self.assertFalse(mock_send.called) self.assertFalse(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -117,7 +117,7 @@ class RetentionNotificationsFlowTests(TestCase):
check_inactive_students_task() check_inactive_students_task()
self.assertFalse(Notification.objects.filter(user=self.student, title="دلمان برایتان تنگ شده!").exists())
self.assertFalse(Notification.objects.filter(user=self.student, title="Мы скучаем по вам!").exists())
self.assertFalse(mock_send.called) self.assertFalse(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -148,7 +148,7 @@ class RetentionNotificationsFlowTests(TestCase):
s2.save() s2.save()
# Check DB notification # Check DB notification
notif = Notification.objects.filter(user=self.student, title="جای شما در کلاس زنده خالی بود!").first()
notif = Notification.objects.filter(user=self.student, title="Пропуск живых уроков").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)

28
apps/account/tests/notifications/test_transaction_notifications.py

@ -12,9 +12,9 @@ from apps.transaction.models import TransactionParticipant
class TransactionNotificationsFlowTests(TestCase): class TransactionNotificationsFlowTests(TestCase):
def setUp(self): def setUp(self):
# Create languages # Create languages
self.lang_fa, _ = Language.objects.update_or_create(
code='fa',
defaults={'name': 'Persian', 'status': True, 'countries': []}
self.lang_ru, _ = Language.objects.update_or_create(
code='ru',
defaults={'name': 'Russian', 'status': True, 'countries': []}
) )
self.lang_en, _ = Language.objects.update_or_create( self.lang_en, _ = Language.objects.update_or_create(
code='en', code='en',
@ -32,7 +32,7 @@ class TransactionNotificationsFlowTests(TestCase):
email='student_tx@example.com', email='student_tx@example.com',
username='student_tx', username='student_tx',
fullname='Tx Student', fullname='Tx Student',
language=self.lang_fa,
language=self.lang_ru,
fcm='token_tx_student' fcm='token_tx_student'
) )
@ -41,7 +41,7 @@ class TransactionNotificationsFlowTests(TestCase):
self.course = Course.objects.create( self.course = Course.objects.create(
title=[ title=[
{"title": "Course 1", "language_code": "en"}, {"title": "Course 1", "language_code": "en"},
{"title": "دوره ۱", "language_code": "fa"}
{"title": "Курс 1", "language_code": "ru"}
], ],
slug=[{"title": "course-1", "language_code": "en"}], slug=[{"title": "course-1", "language_code": "en"}],
category=self.category, category=self.category,
@ -72,10 +72,10 @@ class TransactionNotificationsFlowTests(TestCase):
self.tx.status = TransactionParticipant.TransactionStatus.SUCCESS self.tx.status = TransactionParticipant.TransactionStatus.SUCCESS
self.tx.save() self.tx.save()
# Check DB notification (in Persian)
notif = Notification.objects.filter(user=self.student, title="پرداخت موفقیت‌آمیز").first()
# Check DB notification (in Russian)
notif = Notification.objects.filter(user=self.student, title="Оплата успешна").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -84,10 +84,10 @@ class TransactionNotificationsFlowTests(TestCase):
self.tx.status = TransactionParticipant.TransactionStatus.FAILED self.tx.status = TransactionParticipant.TransactionStatus.FAILED
self.tx.save() self.tx.save()
# Check DB notification (in Persian)
notif = Notification.objects.filter(user=self.student, title="خطا در پرداخت").first()
# Check DB notification (in Russian)
notif = Notification.objects.filter(user=self.student, title="Ошибка оплаты").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification') @patch('apps.account.notification_service.send_notification')
@ -96,8 +96,8 @@ class TransactionNotificationsFlowTests(TestCase):
self.tx.status = TransactionParticipant.TransactionStatus.REFUNDED self.tx.status = TransactionParticipant.TransactionStatus.REFUNDED
self.tx.save() self.tx.save()
# Check DB notification (in Persian)
notif = Notification.objects.filter(user=self.student, title="بازگشت وجه انجام شد").first()
# Check DB notification (in Russian)
notif = Notification.objects.filter(user=self.student, title="Возврат средств выполнен").first()
self.assertIsNotNone(notif) self.assertIsNotNone(notif)
self.assertIn("دوره ۱", notif.message)
self.assertIn("Курс 1", notif.message)
self.assertTrue(mock_send.called) self.assertTrue(mock_send.called)
Loading…
Cancel
Save