Проблема:
- Service Worker файл (sw.js) находился в корне backend/
- Hardcoded пути к иконкам в sw.js и push.py (/static/img/logo-192.png)
- Функция serve_service_worker() в главном urls.py проекта
- Зависимость от project-specific структуры
- Невозможность переиспользовать приложение без изменений
Решение:
Service Worker на месте:
- backend/notifications/static/notifications/sw.js
- backend/notifications/views.py - serve_service_worker()
- backend/notifications/urls.py - добавлен endpoint sw.js
- backend/eusrr_backend/urls.py - импорт view из notifications
Удаление hardcoded путей:
- sw.js: убрана константа icon='/static/img/logo-192.png'
- senders/push.py: убран hardcoded 'icon': '/static/img/logo.png'
- config.py: добавлены PUSH_DEFAULT_ICON, PUSH_DEFAULT_BADGE (None = browser default)
- README.md: документация по настройке через NOTIFICATIONS_CONFIG
Изменения:
- Создан: notifications/views.py с serve_service_worker()
- Создан: notifications/static/notifications/sw.js
- Изменен: notifications/urls.py - добавлен path('sw.js')
- Изменен: notifications/config.py - настройки иконок
- Изменен: notifications/senders/push.py - использование config
- Изменен: notifications/README.md - документация
- Упрощен: eusrr_backend/urls.py - удалена функция, добавлен импорт
- Удалены: backend/sw.js, backend/static/sw.js, backend/communications/sw.js
Преимущества:
- ✅ Полностью автономное приложение
- ✅ Нет зависимостей от структуры проекта
- ✅ Конфигурируемые иконки через settings.py
- ✅ Browser defaults если иконки не указаны
- ✅ Легко переносить между проектами
- ✅ Единообразие архитектуры (SRP)
Верификация:
- python manage.py check - успешно
403 lines
12 KiB
Markdown
403 lines
12 KiB
Markdown
# Django Universal Notifications
|
||
|
||
Универсальная переиспользуемая система уведомлений для Django 5.2+
|
||
|
||
## ✨ Особенности
|
||
|
||
- 🎯 **Простота** - 2 модели вместо 6
|
||
- 🔄 **Универсальность** - GenericForeignKey для любых объектов
|
||
- 📡 **Multi-channel** - WebSocket, Email, Web Push
|
||
- ⚡ **Производительность** - оптимизированные индексы и QuerySet
|
||
- 🎨 **Гибкость** - легко расширяется под любые нужды
|
||
- 🏗️ **Архитектура** - по образу django-notifications-hq
|
||
|
||
## 🚀 Быстрый старт
|
||
|
||
```python
|
||
from notifications.signals_new import notify
|
||
|
||
# Создать уведомление
|
||
notify.send(
|
||
sender=user,
|
||
recipient=other_user,
|
||
verb='liked',
|
||
description='liked your photo',
|
||
action_url='/photos/123/'
|
||
)
|
||
|
||
# Получить уведомления
|
||
unread = user.notifications.unread()
|
||
|
||
# Отметить как прочитанное
|
||
notification.mark_as_read()
|
||
```
|
||
|
||
## 📦 Установка
|
||
|
||
### 1. Скопируйте модуль
|
||
|
||
```bash
|
||
cp -r notifications/ /path/to/your-django-project/
|
||
```
|
||
|
||
### 2. Установите зависимости
|
||
|
||
```bash
|
||
# Основные зависимости
|
||
pip install -r notifications/requirements.txt
|
||
|
||
# Или установите вручную:
|
||
pip install Django>=5.2 djangorestframework celery redis channels channels-redis
|
||
```
|
||
|
||
### 3. Настройте Django
|
||
|
||
Добавьте в `settings.py`:
|
||
|
||
```python
|
||
INSTALLED_APPS = [
|
||
...,
|
||
'channels', # Для WebSocket
|
||
'rest_framework', # Для API
|
||
'notifications', # Модуль уведомлений
|
||
]
|
||
|
||
# Настройки Channels (WebSocket)
|
||
ASGI_APPLICATION = 'your_project.asgi.application'
|
||
CHANNEL_LAYERS = {
|
||
'default': {
|
||
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
||
'CONFIG': {
|
||
'hosts': [('127.0.0.1', 6379)],
|
||
},
|
||
},
|
||
}
|
||
|
||
# Настройки Celery (асинхронные задачи)
|
||
CELERY_BROKER_URL = 'redis://localhost:6379/0'
|
||
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
|
||
```
|
||
|
||
### 4. Подключите URL-ы
|
||
|
||
В `urls.py`:
|
||
|
||
```python
|
||
urlpatterns = [
|
||
...,
|
||
path('api/v1/notifications/', include('notifications.api.urls')),
|
||
]
|
||
```
|
||
|
||
### 5. Примените миграции
|
||
|
||
```bash
|
||
python manage.py migrate notifications
|
||
```
|
||
|
||
**Production-safe миграции:**
|
||
Миграции безопасны для production - используют `DROP TABLE IF EXISTS` для идемпотентности.
|
||
Можно применять на любом окружении без ручной очистки БД.
|
||
|
||
## <20> Структура модуля
|
||
|
||
```
|
||
notifications/
|
||
├── requirements.txt # Зависимости модуля
|
||
├── README.md # Документация
|
||
├── models.py # Модели (Notification, UserChannelPreferences)
|
||
├── signals.py # notify.send() API
|
||
├── channels.py # Роутинг по каналам доставки
|
||
├── config.py # Конфигурация (переопределяемая)
|
||
├── admin.py # Django Admin
|
||
├── api/ # REST API endpoints
|
||
│ ├── views.py # 11 API endpoints
|
||
│ ├── urls.py # URL routing
|
||
│ └── serializers.py # (планируется)
|
||
├── tasks/ # Celery задачи
|
||
│ ├── base.py # Базовый класс с retry/rate limiting
|
||
│ ├── email.py # Email отправка
|
||
│ ├── websocket.py # WebSocket отправка
|
||
│ └── push.py # Push уведомления
|
||
├── senders/ # Низкоуровневые отправители
|
||
├── templates/ # Email и Web шаблоны
|
||
└── migrations/ # Production-safe миграции
|
||
```
|
||
|
||
## 📚 Документация
|
||
|
||
Полная документация: [`backend/docs/guides/NOTIFICATIONS_V2_USAGE.md`](../docs/guides/NOTIFICATIONS_V2_USAGE.md)
|
||
|
||
## 🚧 TODO
|
||
|
||
### Критичные задачи:
|
||
- [ ] Написать unit и integration тесты (coverage >80%)
|
||
- [ ] Создать email шаблоны (notification.html/txt, digest.html/txt)
|
||
- [ ] Убрать хардкод из config.py (сделать полностью переопределяемым)
|
||
|
||
### Важные улучшения:
|
||
- [ ] Добавить DRF serializers для API
|
||
- [ ] Создать notifications/settings.py для централизованной конфигурации
|
||
- [ ] Добавить больше примеров использования
|
||
|
||
### Желательно:
|
||
- [ ] Подготовить setup.py для публикации в PyPI
|
||
- [ ] Sphinx документация
|
||
- [ ] CI/CD pipeline (GitHub Actions)
|
||
|
||
## 🏗️ Архитектура
|
||
|
||
### Модели
|
||
|
||
**Notification** - основная модель уведомлений
|
||
- Структура: `actor` performed `verb` on `action_object` at `target`
|
||
- GenericForeignKey для универсальности
|
||
|
||
**UserChannelPreferences** - настройки каналов доставки
|
||
- Один пользователь - одна запись
|
||
- Настройки для всех каналов (web, email, telegram, push)
|
||
|
||
### Компоненты
|
||
|
||
- `models.py` - модели с QuerySet методами (Notification, UserChannelPreferences)
|
||
- `signals.py` - простой API `notify.send()` для создания уведомлений
|
||
- `channels.py` - автоматический роутинг по каналам (WebSocket, Email, Push)
|
||
- `admin.py` - Django Admin интерфейс для управления
|
||
- `api/` - REST API endpoints (11 эндпоинтов)
|
||
- `tasks/` - Celery задачи с retry и rate limiting
|
||
- `config.py` - централизованная конфигурация
|
||
|
||
## 💡 Примеры
|
||
|
||
### Социальное взаимодействие
|
||
|
||
```python
|
||
# Лайк
|
||
notify.send(
|
||
sender=user,
|
||
recipient=post.author,
|
||
verb='liked',
|
||
target=post,
|
||
description=f'liked your post "{post.title}"',
|
||
action_url=f'/posts/{post.id}/'
|
||
)
|
||
|
||
# Комментарий
|
||
notify.send(
|
||
sender=commenter,
|
||
recipient=post.author,
|
||
verb='commented',
|
||
action_object=comment,
|
||
target=post,
|
||
description='commented on your post',
|
||
action_url=f'/posts/{post.id}/#comment-{comment.id}'
|
||
)
|
||
```
|
||
|
||
### Системные уведомления
|
||
|
||
```python
|
||
# Одобрение документа
|
||
notify.send(
|
||
sender=approver,
|
||
recipient=document.author,
|
||
verb='document_approved',
|
||
action_object=document,
|
||
description=f'Document #{document.id} approved',
|
||
action_url=f'/documents/{document.id}/',
|
||
data={'approved_by': approver.get_full_name()}
|
||
)
|
||
```
|
||
|
||
### Множественные получатели
|
||
|
||
```python
|
||
# Уведомить всю команду
|
||
notify.send(
|
||
sender=manager,
|
||
recipient=team_members, # список пользователей
|
||
verb='meeting_scheduled',
|
||
description='Team meeting tomorrow at 10:00',
|
||
action_url='/calendar/'
|
||
)
|
||
```
|
||
|
||
## ⚙️ Настройка каналов
|
||
|
||
```python
|
||
# Получить настройки пользователя
|
||
prefs = user.channel_preferences
|
||
|
||
# Включить/выключить каналы
|
||
prefs.email_enabled = True
|
||
prefs.push_enabled = False
|
||
prefs.save()
|
||
|
||
# Режим "Не беспокоить"
|
||
prefs.dnd_enabled = True
|
||
prefs.dnd_start_time = '22:00'
|
||
prefs.dnd_end_time = '08:00'
|
||
prefs.save()
|
||
|
||
# Отключить определенные типы
|
||
prefs.disable_verb('liked')
|
||
prefs.disable_verb('followed')
|
||
```
|
||
|
||
## 🧩 Интеграция
|
||
|
||
### WebSocket (Django Channels)
|
||
|
||
Уведомления автоматически отправляются через WebSocket если:
|
||
- Django Channels установлен и настроен
|
||
- `web_enabled=True` в настройках пользователя
|
||
|
||
### Email
|
||
|
||
Поддержка мгновенных уведомлений и дайджестов:
|
||
- `instant` - сразу при создании
|
||
- `daily` - ежедневный дайджест
|
||
- `weekly` - еженедельный дайджест
|
||
|
||
Для дайджестов используйте Celery:
|
||
```python
|
||
from notifications.channels import send_email_digest
|
||
|
||
send_email_digest(user, frequency='daily')
|
||
```
|
||
|
||
### Web Push
|
||
|
||
Требуется:
|
||
- `django-push-notifications` установлен
|
||
- Модель `WebPushSubscription`
|
||
- `push_enabled=True` в настройках
|
||
|
||
## 🎯 Рекомендуемые verb типы
|
||
|
||
Используйте стандартные типы для consistency:
|
||
|
||
**Социальные:**
|
||
- `liked`, `commented`, `shared`, `followed`, `mentioned`, `replied`
|
||
|
||
**Документы:**
|
||
- `document_created`, `document_updated`, `document_approved`, `document_rejected`
|
||
|
||
**Заявки:**
|
||
- `request_created`, `request_approved`, `request_rejected`, `request_completed`
|
||
|
||
**Календарь:**
|
||
- `event_created`, `event_updated`, `event_reminder`, `event_cancelled`
|
||
|
||
**Система:**
|
||
- `system_message`, `reminder`, `alert`, `error`
|
||
|
||
## 📊 QuerySet API
|
||
|
||
```python
|
||
# Фильтрация
|
||
user.notifications.unread() # Непрочитанные
|
||
user.notifications.read() # Прочитанные
|
||
user.notifications.active() # Активные (не удаленные)
|
||
user.notifications.deleted() # Удаленные
|
||
|
||
# Действия
|
||
user.notifications.mark_all_as_read() # Отметить все как прочитанные
|
||
notification.mark_as_read() # Отметить одно как прочитанное
|
||
```
|
||
|
||
## 🔄 Миграция со старых систем
|
||
|
||
Если мигрируете с другой системы уведомлений, см. раздел "Миграция" в полной документации.
|
||
|
||
## 🧪 Тестирование
|
||
|
||
```python
|
||
from notifications.signals_new import notify
|
||
|
||
# Создать тестовое уведомление
|
||
notification = notify.send(
|
||
sender=user1,
|
||
recipient=user2,
|
||
verb='test',
|
||
description='Test notification'
|
||
)
|
||
|
||
assert notification.unread == True
|
||
assert notification.recipient == user2
|
||
```
|
||
|
||
## 📄 Лицензия
|
||
|
||
MIT License - используйте свободно в своих проектах
|
||
|
||
## 🤝 Вклад
|
||
|
||
Приложение разработано как универсальное решение и может использоваться в любых Django проектах.
|
||
|
||
Не стесняйтесь адаптировать под свои нужды!
|
||
|
||
## 🔧 Настройка конфигурации
|
||
|
||
Переопределите настройки в `settings.py` вашего проекта:
|
||
|
||
```python
|
||
# settings.py
|
||
|
||
NOTIFICATIONS_CONFIG = {
|
||
# Общие
|
||
'SITE_NAME': 'Моя Компания',
|
||
'NOTIFICATION_MAX_AGE_DAYS': 90,
|
||
|
||
# Email
|
||
'EMAIL_RATE_LIMIT': '10/m',
|
||
'EMAIL_MAX_RETRIES': 3,
|
||
|
||
# Web Push
|
||
'PUSH_RATE_LIMIT': '50/m',
|
||
'PUSH_DEFAULT_ICON': '/static/img/logo-192.png', # None = browser default
|
||
'PUSH_DEFAULT_BADGE': '/static/img/badge.png', # None = без badge
|
||
|
||
# WebSocket
|
||
'WEBSOCKET_MAX_RETRIES': 1,
|
||
|
||
# DND режим
|
||
'DND_ENABLED': True,
|
||
}
|
||
```
|
||
|
||
**Важно:** Приложение полностью самодостаточное и не требует project-specific путей.
|
||
Если не указать `PUSH_DEFAULT_ICON`, браузер будет использовать свою дефолтную иконку.
|
||
|
||
### Использование в коде
|
||
|
||
```python
|
||
from notifications.config import get, get_config
|
||
|
||
# Получить всю конфигурацию
|
||
config = get_config()
|
||
|
||
# Получить конкретную настройку
|
||
icon_url = get('PUSH_DEFAULT_ICON')
|
||
```
|
||
|
||
## 🚀 Запуск Celery worker
|
||
|
||
Для обработки асинхронных задач:
|
||
|
||
```bash
|
||
# Запуск worker
|
||
celery -A your_project worker -l info
|
||
|
||
# Для периодических задач (digest)
|
||
celery -A your_project beat -l info
|
||
```
|
||
|
||
---
|
||
|
||
**Версия:** 2.0
|
||
**Django:** 5.2+
|
||
**Python:** 3.10+
|
||
**Статус:** ✅ Production-ready
|
||
**Зависимости:** См. `requirements.txt`
|