Replace persisted event statuses with publication and cancellation flags, and compute public lifecycle labels from event timing and registration capacity. Keep filters, registration checks, and profile responses aligned with the derived status.
45 lines
1.5 KiB
Python
45 lines
1.5 KiB
Python
"""Scheduled automatic in-app reminders."""
|
|
|
|
import logging
|
|
from datetime import timedelta
|
|
|
|
from celery import shared_task
|
|
from django.utils import timezone
|
|
|
|
from apps.events.models import Event, Registration
|
|
from apps.notifications.services import notify_user
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@shared_task
|
|
def send_event_reminders():
|
|
reminder_target = timezone.now() + timedelta(hours=24)
|
|
window = timedelta(minutes=30)
|
|
events = Event.objects.filter(
|
|
start_time__range=(reminder_target - window, reminder_target + window),
|
|
is_published=True,
|
|
is_cancelled=False,
|
|
is_deleted=False,
|
|
)
|
|
total_sent = 0
|
|
for event in events:
|
|
registrations = Registration.objects.filter(
|
|
event=event,
|
|
status=Registration.StatusChoices.CONFIRMED,
|
|
is_deleted=False,
|
|
).select_related("user")
|
|
for registration in registrations:
|
|
notify_user(registration.user_id, {
|
|
"type": "event_reminder",
|
|
"title": f"یادآوری برگزاری «{event.title}»",
|
|
"message": "رویداد شما در ۲۴ ساعت آینده برگزار میشود.",
|
|
"level": "info",
|
|
"action_url": f"/events/{event.slug}",
|
|
"entity_type": "event",
|
|
"entity_id": event.id,
|
|
})
|
|
total_sent += 1
|
|
logger.info("Event reminders sent to %s users", total_sent)
|
|
return f"Event reminders sent to {total_sent} users"
|