|
|
|
@ -5,7 +5,74 @@ from apps.account.tasks import send_notification |
|
|
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
def create_and_send_notification(user, title_en, body_en, title_fa, body_fa, service='imam-javad', data=None): |
|
|
|
def resolve_notification_route(notification_type, data): |
|
|
|
""" |
|
|
|
Resolves standard GoRouter paths based on notification type and payload data. |
|
|
|
""" |
|
|
|
if not data or not isinstance(data, dict): |
|
|
|
return None |
|
|
|
|
|
|
|
# Import models dynamically inside function to avoid circular imports |
|
|
|
from apps.course.models.course import Course |
|
|
|
from apps.course.models.live_session import CourseLiveSession |
|
|
|
|
|
|
|
try: |
|
|
|
# Group 1: Course related paths (/course_info?slug=...) |
|
|
|
if notification_type in ['course_registered', 'course_completed', 'new_course_weekly', |
|
|
|
'live_class_rescheduled', 'live_class_cancelled', |
|
|
|
'live_recording_available', 'missed_live_sessions', |
|
|
|
'course_access_granted']: |
|
|
|
course_id = data.get('course_id') |
|
|
|
if not course_id and 'session_id' in data: |
|
|
|
session = CourseLiveSession.objects.filter(id=data['session_id']).first() |
|
|
|
if session: |
|
|
|
course_id = session.course_id |
|
|
|
|
|
|
|
if course_id: |
|
|
|
course = Course.objects.filter(id=course_id).first() |
|
|
|
if course: |
|
|
|
slug = course.slug[0].get('title') if isinstance(course.slug, list) and course.slug else course.slug |
|
|
|
return f"/course_info?slug={slug}" |
|
|
|
|
|
|
|
# Group 2: Lesson path (/lesson?slug=...) |
|
|
|
elif notification_type == 'lesson_completed': |
|
|
|
course_id = data.get('course_id') |
|
|
|
if course_id: |
|
|
|
course = Course.objects.filter(id=course_id).first() |
|
|
|
if course: |
|
|
|
slug = course.slug[0].get('title') if isinstance(course.slug, list) and course.slug else course.slug |
|
|
|
return f"/lesson?slug={slug}" |
|
|
|
|
|
|
|
# Group 3: Quiz path (/course_info/quiz?slug=...) |
|
|
|
elif notification_type == 'low_quiz_result': |
|
|
|
from apps.quiz.models import Quiz |
|
|
|
quiz = Quiz.objects.filter(id=data.get('quiz_id')).first() |
|
|
|
if quiz and quiz.course: |
|
|
|
course = quiz.course |
|
|
|
slug = course.slug[0].get('title') if isinstance(course.slug, list) and course.slug else course.slug |
|
|
|
return f"/course_info/quiz?slug={slug}" |
|
|
|
|
|
|
|
# Group 4: Chat Room path (/chat/chat_details?room_id=...) |
|
|
|
elif notification_type in ['teacher_reply', 'support_reply']: |
|
|
|
room_id = data.get('room_id') |
|
|
|
if room_id: |
|
|
|
return f"/chat/chat_details?room_id={room_id}" |
|
|
|
|
|
|
|
# Group 5: Transactions path |
|
|
|
elif notification_type in ['payment_successful', 'payment_failed', 'refund_completed']: |
|
|
|
return "/profile/transactions" |
|
|
|
|
|
|
|
# Group 6: Home path |
|
|
|
elif notification_type == 'student_inactivity': |
|
|
|
return "/home" |
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
logger.error(f"Error resolving route for type={notification_type}, data={data}: {e}") |
|
|
|
|
|
|
|
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): |
|
|
|
""" |
|
|
|
Creates a Notification record in the database and sends a push notification to FCM. |
|
|
|
Resolves localized title and body based on user.language. |
|
|
|
@ -16,16 +83,33 @@ def create_and_send_notification(user, title_en, body_en, title_fa, body_fa, ser |
|
|
|
title = title_fa if lang_code == 'fa' else title_en |
|
|
|
message = body_fa if lang_code == 'fa' else body_en |
|
|
|
|
|
|
|
# Auto-resolve notification type from data payload if not provided |
|
|
|
if not notification_type and isinstance(data, dict): |
|
|
|
notification_type = data.get('type') |
|
|
|
|
|
|
|
# Auto-resolve GoRouter navigation route if not provided |
|
|
|
if not navigate_to and notification_type: |
|
|
|
navigate_to = resolve_notification_route(notification_type, data) |
|
|
|
|
|
|
|
# Save to database |
|
|
|
notif = Notification.objects.create( |
|
|
|
user=user, |
|
|
|
title=title, |
|
|
|
message=message, |
|
|
|
service=service |
|
|
|
service=service, |
|
|
|
notification_type=notification_type, |
|
|
|
action=action, |
|
|
|
navigate_to=navigate_to |
|
|
|
) |
|
|
|
|
|
|
|
fcm_token = getattr(user, 'fcm', None) |
|
|
|
if fcm_token: |
|
|
|
# Prepare the payload including the new routing properties |
|
|
|
fcm_data = dict(data or {}) |
|
|
|
fcm_data.setdefault('type', notification_type or '') |
|
|
|
fcm_data.setdefault('action', action or '') |
|
|
|
fcm_data.setdefault('navigate_to', navigate_to or '') |
|
|
|
|
|
|
|
try: |
|
|
|
try: |
|
|
|
loop = asyncio.get_event_loop() |
|
|
|
@ -34,9 +118,9 @@ def create_and_send_notification(user, title_en, body_en, title_fa, body_fa, ser |
|
|
|
asyncio.set_event_loop(loop) |
|
|
|
|
|
|
|
if loop.is_running(): |
|
|
|
loop.create_task(send_notification([fcm_token], title, message, data)) |
|
|
|
loop.create_task(send_notification([fcm_token], title, message, fcm_data)) |
|
|
|
else: |
|
|
|
loop.run_until_complete(send_notification([fcm_token], title, message, data)) |
|
|
|
loop.run_until_complete(send_notification([fcm_token], title, message, fcm_data)) |
|
|
|
except Exception as e: |
|
|
|
logger.error(f"Failed to send push notification via FCM: {e}") |
|
|
|
|
|
|
|
|