Проблема: - Монолитный notification_signals.py (~200 строк) смешивал разные concerns - Сложно поддерживать и понимать логику уведомлений - Отсутствовала интеграция с API для уведомлений о лайках Решение: Разделен на модульную структуру feed/notifications/: - config.py - NotificationVerbs, MessageTemplates, ActionURLs, truncate_text - handlers.py - notify_new_post(), notify_comment(), notify_post_reaction(), get_post_recipients() - signals.py - Django signal receivers (@receiver) - __init__.py - публичный API модуля Изменения: - Создан: feed/notifications/ модуль с 4 файлами - Переименован: notification_signals.py → notification_signals.py.old - Изменен: apps.py - обновлен импорт на feed.notifications - Изменен: api/v1/feed/views.py - добавлен вызов notify_post_reaction() в метод like() Преимущества: - ✅ Единообразие с requests_app и procurement - ✅ Четкое разделение ответственности (SRP) - ✅ Легче тестировать отдельные компоненты - ✅ Публичный API через __init__.py - ✅ Уведомления о лайках теперь работают - ✅ Централизованные шаблоны сообщений Верификация: - python manage.py check - успешно
94 lines
3.3 KiB
Python
94 lines
3.3 KiB
Python
"""
|
||
Конфигурация уведомлений для модуля Feed.
|
||
|
||
Содержит:
|
||
- NotificationVerbs - глаголы для уведомлений
|
||
- MessageTemplates - шаблоны сообщений
|
||
- ActionURLs - URL-адреса действий
|
||
"""
|
||
|
||
|
||
class NotificationVerbs:
|
||
"""Глаголы (verbs) для уведомлений feed."""
|
||
|
||
NEW_POST = 'feed_new_post'
|
||
POST_COMMENT = 'feed_post_comment'
|
||
POST_REACTION = 'feed_post_reaction'
|
||
|
||
|
||
class MessageTemplates:
|
||
"""Шаблоны сообщений для уведомлений feed."""
|
||
|
||
@staticmethod
|
||
def new_post_company() -> str:
|
||
"""Шаблон для новости компании."""
|
||
return 'Новая публикация компании'
|
||
|
||
@staticmethod
|
||
def new_post_department(department_name: str) -> str:
|
||
"""Шаблон для новости отдела."""
|
||
return f'Новая публикация отдела {department_name}'
|
||
|
||
@staticmethod
|
||
def new_post_employee(author_name: str) -> str:
|
||
"""Шаблон для личной публикации."""
|
||
return f'Новая публикация от {author_name}'
|
||
|
||
@staticmethod
|
||
def comment(author_name: str, comment_text: str) -> str:
|
||
"""Шаблон для комментария к публикации."""
|
||
return f'{author_name} прокомментировал: {comment_text}'
|
||
|
||
@staticmethod
|
||
def comment_title() -> str:
|
||
"""Заголовок для уведомления о комментарии."""
|
||
return 'Новый комментарий к вашей публикации'
|
||
|
||
@staticmethod
|
||
def reaction(user_name: str, post_title: str) -> str:
|
||
"""Шаблон для реакции на публикацию."""
|
||
return f'{user_name} понравилась публикация "{post_title}"'
|
||
|
||
@staticmethod
|
||
def reaction_title() -> str:
|
||
"""Заголовок для уведомления о реакции."""
|
||
return 'Ваша публикация понравилась'
|
||
|
||
|
||
class ActionURLs:
|
||
"""URL-адреса для действий с публикациями."""
|
||
|
||
# Пока все действия ведут на главную страницу
|
||
# TODO: реализовать прямые ссылки на публикации
|
||
FEED_HOME = '/'
|
||
|
||
@staticmethod
|
||
def post_detail(post_id: int) -> str:
|
||
"""
|
||
Возвращает URL-адрес публикации.
|
||
|
||
TODO: реализовать отдельную страницу публикации
|
||
"""
|
||
return f'/?post={post_id}' # Временное решение
|
||
|
||
|
||
def truncate_text(text: str, max_length: int = 100) -> str:
|
||
"""
|
||
Обрезает текст до указанной длины.
|
||
|
||
Args:
|
||
text: Исходный текст
|
||
max_length: Максимальная длина (по умолчанию 100)
|
||
|
||
Returns:
|
||
Обрезанный текст с многоточием если нужно
|
||
"""
|
||
if not text:
|
||
return ''
|
||
|
||
text = text.strip()
|
||
if len(text) <= max_length:
|
||
return text
|
||
|
||
return text[:max_length - 3] + '...'
|