mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 07:31:07 -05:00
229 lines
7.7 KiB
Python
229 lines
7.7 KiB
Python
from django.core.mail import send_mail
|
|
from django.conf import settings
|
|
from django.template.loader import render_to_string
|
|
from django.utils import timezone
|
|
from django.contrib.auth import get_user_model
|
|
import requests
|
|
import json
|
|
from datetime import timedelta
|
|
from celery import shared_task
|
|
|
|
User = get_user_model()
|
|
|
|
class NotificationDispatcher:
|
|
"""Handles comment notifications and escalations"""
|
|
|
|
def __init__(self):
|
|
self.email_enabled = hasattr(settings, 'EMAIL_HOST')
|
|
self.slack_enabled = hasattr(settings, 'SLACK_WEBHOOK_URL')
|
|
self.sms_enabled = hasattr(settings, 'SMS_API_KEY')
|
|
|
|
def notify_new_comment(self, comment, thread):
|
|
"""Handle notification for a new comment"""
|
|
# Queue immediate notifications
|
|
self.send_in_app_notification.delay(
|
|
user_ids=self._get_thread_participants(thread),
|
|
title="New Comment",
|
|
message=f"New comment on {thread.content_object}",
|
|
link=self._get_thread_url(thread)
|
|
)
|
|
|
|
# Queue email notifications
|
|
self.send_email_notification.delay(
|
|
user_ids=self._get_thread_participants(thread),
|
|
subject=f"New comment on {thread.content_object}",
|
|
template="notifications/new_comment.html",
|
|
context={
|
|
'comment': comment,
|
|
'thread': thread,
|
|
'url': self._get_thread_url(thread)
|
|
}
|
|
)
|
|
|
|
# Schedule Slack escalation if needed
|
|
if self.slack_enabled:
|
|
self.schedule_slack_escalation.apply_async(
|
|
args=[comment.id],
|
|
countdown=24 * 3600 # 24 hours
|
|
)
|
|
|
|
def notify_mention(self, comment, mentioned_users):
|
|
"""Handle notification for @mentions"""
|
|
user_ids = [user.id for user in mentioned_users]
|
|
|
|
# Queue immediate notifications
|
|
self.send_in_app_notification.delay(
|
|
user_ids=user_ids,
|
|
title="Mentioned in Comment",
|
|
message=f"{comment.author} mentioned you in a comment",
|
|
link=self._get_comment_url(comment)
|
|
)
|
|
|
|
# Queue email notifications
|
|
self.send_email_notification.delay(
|
|
user_ids=user_ids,
|
|
subject="You were mentioned in a comment",
|
|
template="notifications/mention.html",
|
|
context={
|
|
'comment': comment,
|
|
'url': self._get_comment_url(comment)
|
|
}
|
|
)
|
|
|
|
# Queue mobile push notifications
|
|
self.send_push_notification.delay(
|
|
user_ids=user_ids,
|
|
title="New Mention",
|
|
message=f"{comment.author} mentioned you: {comment.content[:100]}..."
|
|
)
|
|
|
|
# Schedule SMS escalation if needed
|
|
if self.sms_enabled:
|
|
self.schedule_sms_escalation.apply_async(
|
|
args=[comment.id, user_ids],
|
|
countdown=12 * 3600 # 12 hours
|
|
)
|
|
|
|
def notify_resolution(self, thread, resolver):
|
|
"""Handle notification for thread resolution"""
|
|
self.send_in_app_notification.delay(
|
|
user_ids=self._get_thread_participants(thread),
|
|
title="Thread Resolved",
|
|
message=f"Thread resolved by {resolver}",
|
|
link=self._get_thread_url(thread)
|
|
)
|
|
|
|
@shared_task
|
|
def send_in_app_notification(user_ids, title, message, link):
|
|
"""Send in-app notification to users"""
|
|
from .models import InAppNotification
|
|
for user_id in user_ids:
|
|
InAppNotification.objects.create(
|
|
user_id=user_id,
|
|
title=title,
|
|
message=message,
|
|
link=link
|
|
)
|
|
|
|
@shared_task
|
|
def send_email_notification(user_ids, subject, template, context):
|
|
"""Send email notification to users"""
|
|
if not settings.EMAIL_HOST:
|
|
return
|
|
|
|
users = User.objects.filter(id__in=user_ids)
|
|
for user in users:
|
|
if not user.email:
|
|
continue
|
|
|
|
html_content = render_to_string(template, {
|
|
'user': user,
|
|
**context
|
|
})
|
|
|
|
send_mail(
|
|
subject=subject,
|
|
message='',
|
|
html_message=html_content,
|
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
|
recipient_list=[user.email]
|
|
)
|
|
|
|
@shared_task
|
|
def send_push_notification(user_ids, title, message):
|
|
"""Send mobile push notification"""
|
|
from .models import PushToken
|
|
|
|
tokens = PushToken.objects.filter(
|
|
user_id__in=user_ids,
|
|
active=True
|
|
)
|
|
|
|
if not tokens:
|
|
return
|
|
|
|
# Implementation depends on push notification service
|
|
# Example using Firebase:
|
|
try:
|
|
requests.post(
|
|
settings.FIREBASE_FCM_URL,
|
|
headers={
|
|
'Authorization': f'key={settings.FIREBASE_SERVER_KEY}',
|
|
'Content-Type': 'application/json'
|
|
},
|
|
json={
|
|
'registration_ids': [t.token for t in tokens],
|
|
'notification': {
|
|
'title': title,
|
|
'body': message
|
|
}
|
|
}
|
|
)
|
|
except Exception as e:
|
|
print(f"Push notification failed: {e}")
|
|
|
|
@shared_task
|
|
def schedule_slack_escalation(comment_id):
|
|
"""Send Slack DM escalation for unread comments"""
|
|
from .models import Comment
|
|
|
|
try:
|
|
comment = Comment.objects.get(id=comment_id)
|
|
if not comment.read_by.exists():
|
|
# Send Slack message
|
|
requests.post(
|
|
settings.SLACK_WEBHOOK_URL,
|
|
json={
|
|
'text': (
|
|
f"Unread comment needs attention:\n"
|
|
f"{comment.content}\n"
|
|
f"View: {self._get_comment_url(comment)}"
|
|
)
|
|
}
|
|
)
|
|
except Exception as e:
|
|
print(f"Slack escalation failed: {e}")
|
|
|
|
@shared_task
|
|
def schedule_sms_escalation(comment_id, user_ids):
|
|
"""Send SMS escalation for unread mentions"""
|
|
from .models import Comment
|
|
|
|
try:
|
|
comment = Comment.objects.get(id=comment_id)
|
|
users = User.objects.filter(id__in=user_ids)
|
|
|
|
for user in users:
|
|
if not user.phone_number:
|
|
continue
|
|
|
|
if not comment.read_by.filter(id=user.id).exists():
|
|
# Send SMS using Twilio or similar service
|
|
requests.post(
|
|
settings.SMS_API_URL,
|
|
headers={'Authorization': f'Bearer {settings.SMS_API_KEY}'},
|
|
json={
|
|
'to': user.phone_number,
|
|
'message': (
|
|
f"You were mentioned in a comment that needs attention. "
|
|
f"View: {self._get_comment_url(comment)}"
|
|
)
|
|
}
|
|
)
|
|
except Exception as e:
|
|
print(f"SMS escalation failed: {e}")
|
|
|
|
def _get_thread_participants(self, thread):
|
|
"""Get IDs of all participants in a thread"""
|
|
return list(set(
|
|
[thread.created_by_id] +
|
|
list(thread.comments.values_list('author_id', flat=True))
|
|
))
|
|
|
|
def _get_thread_url(self, thread):
|
|
"""Generate URL for thread"""
|
|
return f"/version-control/comments/thread/{thread.id}/"
|
|
|
|
def _get_comment_url(self, comment):
|
|
"""Generate URL for specific comment"""
|
|
return f"{self._get_thread_url(comment.thread)}#comment-{comment.id}" |