lizerk ed636081dc refactor: complete notifications v2 system with frontend translation
- Remove hard-coded Russian translations from backend API
- Backend now returns raw verb values (language-agnostic)
- Implement frontend translation functions for notification titles and categories
- Add category badge system with filters on notifications page
- Create translation utilities in frontend (verbTranslations.ts)
- Add notification settings page structure
- Update API endpoints to return simplified notification data
- Refactor notification signals across all apps
- Remove deprecated code and tests
- Add comprehensive documentation for v2 migration

Backend changes:
- notifications/api/views.py: Remove translation logic, simplify responses
- All notification_signals.py: Update to use consistent patterns
- Remove deprecated Telegram bot command
- Update Celery tasks for new notification structure

Frontend changes:
- app/notifications/page.tsx: Add translation functions and category badges
- hooks/useNotificationWebSocket.ts: New WebSocket hook for real-time updates
- lib/verbTranslations.ts: Centralized translation mappings
- components/NotificationCenter.tsx: Update to use new API format

This makes the notifications module fully reusable and project-independent.
2026-03-09 21:35:36 +03:00

142 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Базовый класс для Celery задач отправки уведомлений
"""
from abc import ABC, abstractmethod
from celery import shared_task
import logging
logger = logging.getLogger(__name__)
class BaseNotificationTask(ABC):
"""
Абстрактный базовый класс для Celery задач по отправке уведомлений.
Инкапсулирует общую логику:
- Получение notification из БД
- Обработка ошибок
- Логирование
- Retry логика
Наследники реализуют только send_notification() с конкретным sender'ом.
"""
# Настройки Celery для конкретного канала (переопределяются в наследниках)
task_name = None
max_retries = 3
retry_delay = 60 # секунд
rate_limit = None # например '10/m' для email
def __init__(self):
self.logger = logging.getLogger(self.__class__.__name__)
@classmethod
def register_task(cls):
"""
Регистрирует Celery задачу для этого класса.
Должен вызываться при импорте модуля.
"""
instance = cls()
@shared_task(
name=cls.task_name,
bind=True,
max_retries=cls.max_retries,
default_retry_delay=cls.retry_delay,
autoretry_for=(Exception,),
rate_limit=cls.rate_limit,
)
def task_wrapper(self_task, notification_id: int, **kwargs):
"""Wrapper для вызова метода класса из Celery"""
return instance.execute(self_task, notification_id, **kwargs)
return task_wrapper
def execute(self, celery_task, notification_id: int, **kwargs):
"""
Выполняет задачу отправки уведомления.
Args:
celery_task: Объект Celery task (для retry)
notification_id: ID уведомления
**kwargs: Дополнительные параметры для sender
Returns:
True если успешно, False иначе
"""
try:
# Получаем уведомление из БД
notification = self.get_notification(notification_id)
if not notification:
self.logger.warning(
f"⚠️ Notification {notification_id} not found "
f"(possibly deleted by user before delivery)"
)
return False
# Отправляем через конкретный sender
success = self.send_notification(notification, **kwargs)
if success:
self.log_success(notification)
else:
self.log_failure(notification)
return success
except Exception as exc:
self.log_error(notification_id, exc)
raise celery_task.retry(exc=exc)
def get_notification(self, notification_id: int):
"""Получает Notification из БД"""
try:
from notifications.models import Notification
return Notification.objects.get(id=notification_id)
except Exception:
return None
@abstractmethod
def send_notification(self, notification, **kwargs) -> bool:
"""
Отправляет уведомление через конкретный канал.
Должен быть реализован в наследниках.
Args:
notification: Объект Notification
**kwargs: Дополнительные параметры
Returns:
True если успешно, False иначе
"""
pass
def log_success(self, notification):
"""Логирует успешную отправку"""
self.logger.info(
f"✅ Notification sent: "
f"id={notification.id}, "
f"recipient={notification.recipient.id}, "
f"channel={self.__class__.__name__}"
)
def log_failure(self, notification):
"""Логирует неуспешную отправку"""
self.logger.warning(
f"⚠️ Notification failed: "
f"id={notification.id}, "
f"recipient={notification.recipient.id}, "
f"channel={self.__class__.__name__}"
)
def log_error(self, notification_id: int, error: Exception):
"""Логирует ошибку"""
self.logger.error(
f"❌ Task error: "
f"notification_id={notification_id}, "
f"channel={self.__class__.__name__}, "
f"error={type(error).__name__}: {error}",
exc_info=True
)