Browse Source

chat notifications implemented

master
Mohsen Taba 2 weeks ago
parent
commit
df22e10eaf
  1. 184
      apps/account/tests/notifications/test_communication_notifications.py
  2. 3
      apps/chat/apps.py
  3. 100
      apps/chat/signals.py

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

@ -0,0 +1,184 @@
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.participant import Participant
from apps.chat.models import RoomMessage, ChatMessage
class CommunicationNotificationsFlowTests(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_comm@example.com',
username='student_comm',
fullname='Comm Student',
language=self.lang_fa,
fcm='token_comm_student'
)
# Create teacher user
self.teacher = User.objects.create(
email='teacher_comm@example.com',
username='teacher_comm',
fullname='Teacher Comm',
user_type='professor',
is_active=True
)
# Create support user (admin)
self.support = User.objects.create(
email='support_comm@example.com',
username='support_comm',
fullname='Support Comm',
user_type='admin',
is_active=True
)
# Create Course
thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg')
self.course = Course.objects.create(
title=[
{"title": "Course 1", "language_code": "en"},
{"title": "دوره ۱", "language_code": "fa"}
],
slug=[{"title": "course-1", "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": "ongoing", "language_code": "en"}],
is_free=True,
)
# Enroll student in the course
self.participant = Participant.objects.create(
student=self.student,
course=self.course,
is_active=True
)
@patch('apps.account.notification_service.send_notification')
def test_teacher_replied_private_chat(self, mock_send):
# Create a private chat room between student and teacher
room = RoomMessage.objects.create(
name="Private chat with teacher",
initiator=self.student,
recipient=self.teacher,
room_type=RoomMessage.RoomTypeChoices.PRIVATE
)
# Teacher sends a message
ChatMessage.objects.create(
room=room,
sender=self.teacher,
content="Hello from teacher",
content_type=ChatMessage.ChatTypeChoices.TEXT
)
# Verify notification sent to the student
notif = Notification.objects.filter(user=self.student, title="پیام جدید از طرف استاد").first()
self.assertIsNotNone(notif)
self.assertIn("Hello from teacher", notif.message)
self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification')
def test_support_replied_private_chat(self, mock_send):
# Create a private chat room between student and support
room = RoomMessage.objects.create(
name="Support chat",
initiator=self.student,
recipient=self.support,
room_type=RoomMessage.RoomTypeChoices.PRIVATE
)
# Support agent sends a message
ChatMessage.objects.create(
room=room,
sender=self.support,
content="How can I help you?",
content_type=ChatMessage.ChatTypeChoices.TEXT
)
# Verify notification sent to the student
notif = Notification.objects.filter(user=self.student, title="پاسخ پشتیبانی").first()
self.assertIsNotNone(notif)
self.assertIn("How can I help you?", notif.message)
self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification')
def test_teacher_posted_in_course_chat(self, mock_send):
# Create a course chat room
room = RoomMessage.objects.create(
name="Course group chat",
course=self.course,
initiator=self.teacher,
room_type=RoomMessage.RoomTypeChoices.GROUP
)
# Teacher sends a message to course chat
ChatMessage.objects.create(
room=room,
sender=self.teacher,
content="Hello class, remember the homework",
content_type=ChatMessage.ChatTypeChoices.TEXT
)
# Verify notification sent to the student enrolled
notif = Notification.objects.filter(user=self.student, title="پیام استاد در گفتگوی دوره").first()
self.assertIsNotNone(notif)
self.assertIn("homework", notif.message)
self.assertIn("دوره ۱", notif.message)
self.assertTrue(mock_send.called)
@patch('apps.account.notification_service.send_notification')
def test_student_message_no_notification(self, mock_send):
# Create a private chat room
room = RoomMessage.objects.create(
name="Private chat",
initiator=self.student,
recipient=self.teacher,
room_type=RoomMessage.RoomTypeChoices.PRIVATE
)
# Clear notifications
Notification.objects.filter(user=self.student).delete()
mock_send.reset_mock()
# Student sends a message
ChatMessage.objects.create(
room=room,
sender=self.student,
content="Hello professor",
content_type=ChatMessage.ChatTypeChoices.TEXT
)
# Student should not receive a notification for their own message
self.assertFalse(Notification.objects.filter(user=self.student).exists())
self.assertFalse(mock_send.called)

3
apps/chat/apps.py

@ -4,3 +4,6 @@ from django.apps import AppConfig
class ChatConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.chat'
def ready(self):
import apps.chat.signals

100
apps/chat/signals.py

@ -0,0 +1,100 @@
import logging
from django.db.models.signals import post_save
from django.dispatch import receiver
from apps.chat.models import ChatMessage, RoomMessage
from apps.account.models import User
from apps.account.notification_service import create_and_send_notification
from apps.course.models.course import get_localized_field
from apps.course.models.participant import Participant
logger = logging.getLogger(__name__)
def get_message_preview(instance, lang='fa'):
if instance.content_type == 'text':
preview = instance.content or ''
if len(preview) > 50:
return preview[:50] + '...'
return preview
elif instance.content_type == 'image':
return 'تصویر' if lang == 'fa' else 'Image'
elif instance.content_type == 'audio':
return 'صدا' if lang == 'fa' else 'Audio'
else:
return 'فایل ضمیمه' if lang == 'fa' else 'Attachment'
@receiver(post_save, sender=ChatMessage)
def notify_on_new_chat_message(sender, instance, created, **kwargs):
if not created:
return
sender_user = instance.sender
room = instance.room
# 1. Check if the message is in a PRIVATE room
if room.room_type == RoomMessage.RoomTypeChoices.PRIVATE:
# Determine the recipient user (the other person in the private room)
recipient_user = None
if room.initiator == sender_user:
recipient_user = room.recipient
else:
recipient_user = room.initiator
if not recipient_user:
return
# Case A: Teacher Replied in a Private Chat
if sender_user.user_type == User.UserType.PROFESSOR:
if recipient_user.user_type in [User.UserType.STUDENT, User.UserType.CLIENT]:
preview_en = get_message_preview(instance, 'en')
preview_fa = get_message_preview(instance, 'fa')
create_and_send_notification(
user=recipient_user,
title_en="New Message from Teacher",
body_en=f"Teacher {sender_user.fullname or sender_user.username} replied: {preview_en}",
title_fa="پیام جدید از طرف استاد",
body_fa=f"استاد {sender_user.fullname or sender_user.username} پاسخ داد: {preview_fa}",
service='imam-javad',
data={'type': 'teacher_reply_private', 'message_id': instance.id, 'room_id': room.id}
)
# Case B: Support Replied
elif sender_user.user_type in [User.UserType.ADMIN, User.UserType.SUPER_ADMIN, User.UserType.CONSULTANT]:
if recipient_user.user_type in [User.UserType.STUDENT, User.UserType.CLIENT]:
preview_en = get_message_preview(instance, 'en')
preview_fa = get_message_preview(instance, 'fa')
create_and_send_notification(
user=recipient_user,
title_en="New Message from Support",
body_en=f"Support agent {sender_user.fullname or sender_user.username} replied to your message: {preview_en}",
title_fa="پاسخ پشتیبانی",
body_fa=f"پشتیبان {sender_user.fullname or sender_user.username} به پیام شما پاسخ داد: {preview_fa}",
service='imam-javad',
data={'type': 'support_reply', 'message_id': instance.id, 'room_id': room.id}
)
# 2. Check if the message is in a GROUP/COURSE room
elif room.room_type == RoomMessage.RoomTypeChoices.GROUP and room.course:
# Case A: Teacher Replied in a Course Chat
if sender_user.user_type == User.UserType.PROFESSOR:
course = room.course
course_title_en = get_localized_field('en', course.title)
course_title_fa = get_localized_field('fa', course.title)
preview_en = get_message_preview(instance, 'en')
preview_fa = get_message_preview(instance, 'fa')
# Notify all active enrolled students of the course
participants = Participant.objects.filter(course=course, is_active=True).select_related('student')
for p in participants:
if p.student != sender_user: # Exclude sender
create_and_send_notification(
user=p.student,
title_en="Teacher Post in Course Chat",
body_en=f"Teacher {sender_user.fullname or sender_user.username} posted in '{course_title_en}': {preview_en}",
title_fa="پیام استاد در گفتگوی دوره",
body_fa=f"استاد {sender_user.fullname or sender_user.username} در گفتگوی دوره «{course_title_fa}» پیام جدیدی فرستاد: {preview_fa}",
service='imam-javad',
data={'type': 'teacher_reply_course', 'message_id': instance.id, 'room_id': room.id}
)
Loading…
Cancel
Save