lizerk b0e88e8e8b refactor(backend): migrate calendar_app to scheduling app
- Rename calendar_app → scheduling (integration app for django-scheduler)
- Move schedule_patch.py → scheduling/patch.py with improved logging
- Create scheduling.notifications system for django-scheduler events
- Add scheduling.rules for django-rules integration
- Remove unused calendar_app models and API (not registered in urls)
- Remove backend/api/v1/calendar/ (dead code)
- Remove old tests for calendar_app
- Add comprehensive documentation in scheduling/README.md
- Update settings.py: calendar_app.apps.CalendarAppConfig → scheduling.apps.SchedulingConfig
- Clean api/apps.py: remove schedule_patch import (now in scheduling.apps)

The scheduling app provides:
- Patches for django-scheduler bugs (byweekday fix)
- Notification system for calendar events
- Access rules via django-rules
- Auto-applies on Django startup

Closes integration of django-scheduler for EUSRR calendar system.
2026-03-10 15:21:28 +03:00

225 lines
8.4 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.

"""
Бизнес-логика отправки уведомлений для django-scheduler.
Функции:
- get_event_recipients - определение получателей уведомлений
- notify_event_created - уведомление о новом событии
- notify_event_changed - уведомление об изменении события
- notify_event_cancelled - уведомление об отмене события
"""
import logging
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
logger = logging.getLogger(__name__)
Employee = get_user_model()
def get_event_recipients(event) -> list:
"""
Возвращает список получателей уведомлений для события django-scheduler.
Args:
event: Объект schedule.Event
Returns:
list: Список пользователей (Employee) с доступом к календарю события
"""
from schedule.models import CalendarRelation
if not event.calendar:
return []
# Получаем всех пользователей с доступом к календарю
user_ct = ContentType.objects.get_for_model(Employee)
relations = CalendarRelation.objects.filter(
calendar=event.calendar,
content_type=user_ct,
object_id__isnull=False
)
# Собираем активных пользователей
user_ids = relations.values_list('object_id', flat=True)
recipients = list(Employee.objects.filter(
id__in=user_ids,
is_active=True
))
return recipients
def notify_event_created(event, creator=None):
"""
Отправляет уведомления о новом событии всем участникам календаря.
Args:
event: Объект schedule.Event
creator: Пользователь, создавший событие (исключается из получателей)
"""
try:
from notifications.signals import notify
from .config import (
NotificationVerbs, MessageTemplates, ActionURLs, format_date
)
recipients = get_event_recipients(event)
# Исключаем создателя события
if creator:
recipients = [r for r in recipients if r.id != creator.id]
if not recipients:
return
# Формируем сообщение
event_date = format_date(event.start)
calendar_name = event.calendar.name if event.calendar else None
description = MessageTemplates.event_created(
event.title,
event_date,
calendar_name
)
# Отправляем уведомления
for recipient in recipients:
notify.send(
sender=creator,
recipient=recipient,
verb=NotificationVerbs.EVENT_CREATED,
action_object=event,
description=description,
action_url=ActionURLs.CALENDAR,
data={
'title': MessageTemplates.event_created_title(),
'event_id': event.id,
'event_title': event.title,
'event_start': (
event.start.isoformat() if event.start else None
),
'calendar_id': (
event.calendar.id if event.calendar else None
),
'calendar_name': calendar_name,
'creator_id': creator.id if creator else None,
}
)
logger.info(
f"Отправлены уведомления о создании события '{event.title}' "
f"для {len(recipients)} получателей"
)
except Exception as e:
logger.error(
f"Ошибка при отправке уведомлений о создании события: {e}",
exc_info=True
)
def notify_event_changed(
event,
changed_fields: list[str] = None,
modifier=None
):
"""
Отправляет уведомления об изменении события.
Args:
event: Объект schedule.Event
changed_fields: Список изменённых полей
modifier: Пользователь, изменивший событие
"""
try:
from notifications.signals import notify
from .config import (
NotificationVerbs, MessageTemplates, ActionURLs, format_changes
)
recipients = get_event_recipients(event)
# Исключаем модификатора
if modifier:
recipients = [r for r in recipients if r.id != modifier.id]
if not recipients:
return
# Формируем сообщение об изменениях
changes_text = format_changes(changed_fields) if changed_fields else None
description = MessageTemplates.event_changed(event.title, changes_text)
# Отправляем уведомления
for recipient in recipients:
notify.send(
sender=modifier,
recipient=recipient,
verb=NotificationVerbs.EVENT_CHANGED,
action_object=event,
description=description,
action_url=ActionURLs.CALENDAR,
data={
'title': MessageTemplates.event_changed_title(),
'event_id': event.id,
'event_title': event.title,
'changed_fields': changed_fields,
'event_start': event.start.isoformat() if event.start else None,
'calendar_id': event.calendar.id if event.calendar else None,
'modifier_id': modifier.id if modifier else None,
}
)
logger.info(f"Отправлены уведомления об изменении события '{event.title}' для {len(recipients)} получателей")
except Exception as e:
logger.error(f"Ошибка при отправке уведомлений об изменении события: {e}", exc_info=True)
def notify_event_cancelled(event, canceller=None):
"""
Отправляет уведомления об отмене (удалении) события.
Args:
event: Объект schedule.Event
canceller: Пользователь, отменивший событие
"""
try:
from notifications.signals import notify
from .config import NotificationVerbs, MessageTemplates, ActionURLs, format_date
recipients = get_event_recipients(event)
# Исключаем отменившего
if canceller:
recipients = [r for r in recipients if r.id != canceller.id]
if not recipients:
return
# Формируем сообщение
event_date = format_date(event.start)
description = MessageTemplates.event_cancelled(event.title, event_date)
# Отправляем уведомления
for recipient in recipients:
notify.send(
sender=canceller,
recipient=recipient,
verb=NotificationVerbs.EVENT_CANCELLED,
description=description,
action_url=ActionURLs.CALENDAR,
data={
'title': MessageTemplates.event_cancelled_title(),
'event_id': event.id,
'event_title': event.title,
'event_start': event.start.isoformat() if event.start else None,
'calendar_id': event.calendar.id if event.calendar else None,
'canceller_id': canceller.id if canceller else None,
}
)
logger.info(f"Отправлены уведомления об отмене события '{event.title}' для {len(recipients)} получателей")
except Exception as e:
logger.error(f"Ошибка при отправке уведомлений об отмене события: {e}", exc_info=True)