From c630205002a703a02e0f4770315cee3504d11ff3 Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Sat, 11 Jul 2026 08:50:14 +0330 Subject: [PATCH] make notification script added --- .../commands/send_test_notifications.py | 115 ++++++++++++++++++ .../test_communication_notifications.py | 6 +- .../test_retention_notifications.py | 5 +- entrypoint.sh | 1 + 4 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 apps/account/management/commands/send_test_notifications.py diff --git a/apps/account/management/commands/send_test_notifications.py b/apps/account/management/commands/send_test_notifications.py new file mode 100644 index 0000000..7c6eea6 --- /dev/null +++ b/apps/account/management/commands/send_test_notifications.py @@ -0,0 +1,115 @@ +import time +from django.core.management.base import BaseCommand +from django.contrib.auth import get_user_model +from apps.account.notification_service import create_and_send_notification + +class Command(BaseCommand): + help = 'Sends all non-live/non-chat test notifications to a specific user by email.' + + def handle(self, *args, **options): + email = 's.hosseintaba98@gmail.com' + User = get_user_model() + user = User.objects.filter(email=email).first() + + if not user: + self.stdout.write(self.style.ERROR(f"❌ User with email '{email}' not found.")) + return + + self.stdout.write(self.style.SUCCESS(f"🚀 Found user: {user.username} (FCM token: {getattr(user, 'fcm', 'None')})")) + + if not getattr(user, 'fcm', None): + self.stdout.write(self.style.WARNING("⚠️ Warning: This user has no FCM token registered. Notifications will only be saved in the database.")) + + notifications_to_send = [ + # 1. Learning Process + { + "name": "1. Course Registered", + "title_en": "Course Registration Successful", + "body_en": "You have successfully registered for the course 'Quranic Studies'.", + "title_fa": "ثبت‌نام دوره موفقیت‌آمیز بود", + "body_fa": "ثبت‌نام شما در دوره «مطالعات قرآنی» با موفقیت انجام شد.", + "data": {"type": "course_registered", "course_id": "1"} + }, + { + "name": "2. Lesson Completed", + "title_en": "Lesson Completed", + "body_en": "Congratulations! You completed the lesson 'Introduction to Surah Al-Fatiha'.", + "title_fa": "درس به اتمام رسید", + "body_fa": "تبریک! شما درس «آشنایی با سوره فاتحه» را به پایان رساندید.", + "data": {"type": "lesson_completed", "course_id": "1", "lesson_id": "1"} + }, + { + "name": "3. Course Completed", + "title_en": "Course Completed", + "body_en": "Well done! You have completed the course 'Quranic Studies'.", + "title_fa": "دوره به اتمام رسید", + "body_fa": "آفرین! شما دوره «مطالعات قرآنی» را با موفقیت به پایان رساندید.", + "data": {"type": "course_completed", "course_id": "1"} + }, + # 2. Quizzes and Progress + { + "name": "4. Low Quiz Score Suggestion", + "title_en": "Quiz Retake Suggestion", + "body_en": "You scored below the passing threshold on quiz 'Final Exam'. We suggest taking it again to improve your score.", + "title_fa": "پیشنهاد شرکت مجدد در آزمون", + "body_fa": "امتیاز شما در آزمون «امتحان نهایی» کمتر از حد نصاب شده است. پیشنهاد می‌کنیم مجدداً در این آزمون شرکت کنید تا نمره خود را بهبود ببخشید.", + "data": {"type": "low_quiz_result", "quiz_id": "1", "days_since_failure": "2"} + }, + # 3. Transactions and Finance + { + "name": "5. Payment Successful", + "title_en": "Payment Successful", + "body_en": "Your payment for course 'Quranic Studies' was successful. Thank you for your purchase!", + "title_fa": "پرداخت موفقیت‌آمیز", + "body_fa": "پرداخت شما برای دوره «مطالعات قرآنی» موفقیت‌آمیز بود. از خرید شما سپاسگزاریم!", + "data": {"type": "payment_successful", "course_id": "1"} + }, + { + "name": "6. Payment Failed", + "title_en": "Payment Failed", + "body_en": "We encountered an issue processing your payment for 'Quranic Studies'. Please try again.", + "title_fa": "خطا در پرداخت", + "body_fa": "در پردازش پرداخت شما برای دوره «مطالعات قرآنی» مشکلی رخ داد. لطفاً دوباره تلاش کنید.", + "data": {"type": "payment_failed", "course_id": "1"} + }, + { + "name": "7. Refund Completed", + "title_en": "Refund Completed", + "body_en": "A refund has been successfully completed for the course 'Quranic Studies'.", + "title_fa": "بازگشت وجه انجام شد", + "body_fa": "بازگشت وجه برای دوره «مطالعات قرآنی» با موفقیت انجام شد.", + "data": {"type": "refund_completed", "course_id": "1"} + }, + # 4. Retention and Motivation + { + "name": "8. Student Inactivity", + "title_en": "We Miss You!", + "body_en": "You haven't taken any lessons in the last week. Come back and continue your learning journey!", + "title_fa": "دلمان برایتان تنگ شده!", + "body_fa": "در یک هفته گذشته هیچ درسی را مطالعه نکرده‌اید. منتظرتان هستیم تا مسیر یادگیری خود را ادامه دهید!", + "data": {"type": "student_inactivity"} + } + ] + + self.stdout.write(self.style.SUCCESS(f"Sending {len(notifications_to_send)} notifications (with a 2-second interval)...")) + + for index, item in enumerate(notifications_to_send, 1): + self.stdout.write(f"[{index}/{len(notifications_to_send)}] Sending notification: '{item['name']}'...") + try: + create_and_send_notification( + user=user, + title_en=item['title_en'], + body_en=item['body_en'], + title_fa=item['title_fa'], + body_fa=item['body_fa'], + service='imam-javad', + data=item['data'] + ) + self.stdout.write(self.style.SUCCESS(f" Sent successfully!")) + except Exception as e: + self.stdout.write(self.style.ERROR(f" Failed to send: {e}")) + + if index < len(notifications_to_send): + time.sleep(2) + + self.stdout.write(self.style.SUCCESS("🎉 All test notifications processed successfully!")) diff --git a/apps/account/tests/notifications/test_communication_notifications.py b/apps/account/tests/notifications/test_communication_notifications.py index 30fc6d1..4d027cc 100644 --- a/apps/account/tests/notifications/test_communication_notifications.py +++ b/apps/account/tests/notifications/test_communication_notifications.py @@ -43,7 +43,8 @@ class CommunicationNotificationsFlowTests(TestCase): username='teacher_comm', fullname='Teacher Comm', user_type='professor', - is_active=True + is_active=True, + language=self.lang_fa ) # Create support user (admin) @@ -52,7 +53,8 @@ class CommunicationNotificationsFlowTests(TestCase): username='support_comm', fullname='Support Comm', user_type='admin', - is_active=True + is_active=True, + language=self.lang_fa ) # Create Course diff --git a/apps/account/tests/notifications/test_retention_notifications.py b/apps/account/tests/notifications/test_retention_notifications.py index f6ca037..0a519f0 100644 --- a/apps/account/tests/notifications/test_retention_notifications.py +++ b/apps/account/tests/notifications/test_retention_notifications.py @@ -112,6 +112,9 @@ class RetentionNotificationsFlowTests(TestCase): # Manually force completed_at to be 2 days ago (since auto_now_add makes it now) LessonCompletion.objects.filter(id=completion.id).update(completed_at=timezone.now() - datetime.timedelta(days=2)) + # Reset mock_send because LessonCompletion creation triggered a "Lesson Completed" notification + mock_send.reset_mock() + check_inactive_students_task() self.assertFalse(Notification.objects.filter(user=self.student, title="دلمان برایتان تنگ شده!").exists()) @@ -147,5 +150,5 @@ class RetentionNotificationsFlowTests(TestCase): # Check DB notification notif = Notification.objects.filter(user=self.student, title="جای شما در کلاس زنده خالی بود!").first() self.assertIsNotNone(notif) - self.assertIn("Course 1", notif.message) + self.assertIn("دوره ۱", notif.message) self.assertTrue(mock_send.called) diff --git a/entrypoint.sh b/entrypoint.sh index 63d677e..4c38575 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -6,6 +6,7 @@ python manage.py migrate # python manage.py compilemessages python manage.py collectstatic --noinput python manage.py assign_volume_images --force +python manage.py send_test_notifications # python manage.py set_default_category_icons # python manage.py set_hadiscorrection_fixed_text # Seed Russian data (only runs once, skips if data exists)