BREAKING CHANGES: - Удалена старая система (6 моделей → 2 модели) - models_new.py → models.py (Notification, UserChannelPreferences) - signals_new.py → signals.py (notify.send API) - admin_new.py → admin.py Новая архитектура: - Все отправки через Celery (полностью асинхронно) - Модульная структура tasks/ (base, email, push, websocket) - Каждый канал - отдельный класс задачи наследующий BaseNotificationTask - Rate limiting, retry, приоритеты из коробки Обратная совместимость: - Создан services.py facade для старого API - NotificationService.create_notification() работает через notify.send() - Старый код продолжает работать без изменений Удалено: - Старые models.py, signals.py, admin.py, tasks.py (→ .old) - telegram_bot.py, telegram_models.py (Telegram отключен) - test_views.py, views.py, urls.py (устаревшие) Создано: - tasks/ модуль с классовой архитектурой (как senders/) - tasks/base.py - BaseNotificationTask - tasks/email.py - EmailNotificationTask + DigestEmailTask - tasks/push.py - PushNotificationTask - tasks/websocket.py - WebSocketNotificationTask Обновлено: - apps.py - загружает signals, channels, tasks - channels.py - все отправки через Celery задачи - Все импорты models_new → models
122 lines
4.1 KiB
Python
122 lines
4.1 KiB
Python
"""
|
|
Сигнал notify для создания уведомлений
|
|
По образу django-notifications-hq
|
|
|
|
Использование:
|
|
from notifications.signals import notify
|
|
|
|
notify.send(
|
|
sender=user,
|
|
recipient=other_user,
|
|
verb='liked',
|
|
action_object=comment,
|
|
target=post,
|
|
description='liked your comment on "Post Title"',
|
|
action_url='/posts/123/',
|
|
)
|
|
"""
|
|
|
|
from django.dispatch import Signal
|
|
|
|
|
|
# Сигнал для создания уведомлений
|
|
notify = Signal()
|
|
|
|
|
|
def create_notification_handler(sender, **kwargs):
|
|
"""
|
|
Обработчик сигнала notify
|
|
Создает уведомление в БД
|
|
|
|
Параметры:
|
|
sender: Объект-актор (кто создал уведомление)
|
|
recipient: User или список User (кому)
|
|
verb: str - действие (обязательно)
|
|
action_object: Объект действия (опционально)
|
|
target: Целевой объект (опционально)
|
|
description: str - описание (опционально)
|
|
action_url: str - URL для перехода (опционально)
|
|
data: dict - дополнительные данные (опционально)
|
|
public: bool - публичное ли (по умолчанию True)
|
|
timestamp: datetime - время создания (по умолчанию now)
|
|
|
|
Возвращает:
|
|
Notification или список Notification
|
|
"""
|
|
from .models import Notification
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
User = get_user_model()
|
|
|
|
# Извлекаем параметры
|
|
recipient = kwargs.pop('recipient', None)
|
|
verb = kwargs.pop('verb', None)
|
|
action_object = kwargs.pop('action_object', None)
|
|
target = kwargs.pop('target', None)
|
|
description = kwargs.pop('description', None)
|
|
action_url = kwargs.pop('action_url', None)
|
|
data = kwargs.pop('data', {})
|
|
public = kwargs.pop('public', True)
|
|
timestamp = kwargs.pop('timestamp', None)
|
|
|
|
# Валидация
|
|
if not recipient:
|
|
raise ValueError('recipient is required')
|
|
if not verb:
|
|
raise ValueError('verb is required')
|
|
|
|
# Поддержка множественных получателей
|
|
recipients = recipient if isinstance(recipient, (list, tuple)) else [recipient]
|
|
|
|
# Создаем уведомления
|
|
notifications = []
|
|
|
|
for recip in recipients:
|
|
if not isinstance(recip, User):
|
|
raise ValueError(f'recipient must be User instance, got {type(recip)}')
|
|
|
|
# Подготовка данных для GenericForeignKey
|
|
new_notification = Notification(
|
|
recipient=recip,
|
|
verb=verb,
|
|
description=description or '',
|
|
action_url=action_url or '',
|
|
data=data,
|
|
public=public,
|
|
)
|
|
|
|
# Actor
|
|
if sender:
|
|
new_notification.actor_content_type = ContentType.objects.get_for_model(sender)
|
|
new_notification.actor_object_id = sender.pk
|
|
|
|
# Action Object
|
|
if action_object:
|
|
new_notification.action_object_content_type = ContentType.objects.get_for_model(action_object)
|
|
new_notification.action_object_object_id = action_object.pk
|
|
|
|
# Target
|
|
if target:
|
|
new_notification.target_content_type = ContentType.objects.get_for_model(target)
|
|
new_notification.target_object_id = target.pk
|
|
|
|
# Timestamp
|
|
if timestamp:
|
|
new_notification.timestamp = timestamp
|
|
|
|
new_notification.save()
|
|
notifications.append(new_notification)
|
|
|
|
# Возвращаем одно уведомление или список
|
|
if len(notifications) == 1:
|
|
return notifications[0]
|
|
return notifications
|
|
|
|
|
|
# Подключаем обработчик
|
|
notify.connect(
|
|
create_notification_handler,
|
|
dispatch_uid='notifications.create_notification'
|
|
)
|