diff --git a/aleksis/apps/chronos/model_extensions.py b/aleksis/apps/chronos/model_extensions.py index 096b43e22c2c8094d547bbec57f70619cecb99e6..ce6c1810fd461edf10b6a18238c5d38712ce33a4 100644 --- a/aleksis/apps/chronos/model_extensions.py +++ b/aleksis/apps/chronos/model_extensions.py @@ -169,19 +169,4 @@ def send_notifications(sender: Revision, **kwargs): if change.deleted: continue - dt_start, dt_end = change.instance.time_range - dt_start = dt_start.replace(tzinfo=zoneinfo.ZoneInfo(settings.TIME_ZONE)) - dt_end = dt_end.replace(tzinfo=zoneinfo.ZoneInfo(settings.TIME_ZONE)) - - send_time = get_site_preferences()["chronos__time_for_sending_notifications"] - - start_range = timezone.now().replace(hour=send_time.hour, minute=send_time.minute) - if timezone.now().time() > send_time: - start_range = start_range - timedelta(days=1) - end_range = start_range + timedelta(days=1) - - if dt_start <= end_range and dt_end >= start_range: - # Skip this because it's not in the current range for notifications - continue - send_notifications_for_object(change.instance) diff --git a/aleksis/apps/chronos/preferences.py b/aleksis/apps/chronos/preferences.py index 6391b696b3852d7b281a94366e04b5a3bc3fd27e..7b3857c0b5f11c04e0753f50ac1576df0859c783 100644 --- a/aleksis/apps/chronos/preferences.py +++ b/aleksis/apps/chronos/preferences.py @@ -71,13 +71,23 @@ class AffectedGroupsUseParentGroups(BooleanPreference): ) +@site_preferences_registry.register +class DaysInAdvanceNotifications(IntegerPreference): + section = chronos + name = "days_in_advance_notifications" + default = 1 + verbose_name = _("How many days in advance users should be notified about timetable changes?") + @site_preferences_registry.register class TimeForSendingNotifications(TimePreference): section = chronos name = "time_for_sending_notifications" default = time(17, 00) - verbose_name = _("Time for sending notifications for the next day") + verbose_name = _("Time for sending notifications about timetable changes") required = True + help_text = _("This is only used for scheduling notifications " + "which doesn't affect the time period configured above. " + "All other notifications affecting the next days are sent immediately.") @site_preferences_registry.register diff --git a/aleksis/apps/chronos/tasks.py b/aleksis/apps/chronos/tasks.py deleted file mode 100644 index 90f3ed3eacdaccab2ebd7008d8976e4d49b7798b..0000000000000000000000000000000000000000 --- a/aleksis/apps/chronos/tasks.py +++ /dev/null @@ -1,25 +0,0 @@ -from django.utils import timezone - -from aleksis.apps.chronos.models import ( - Event, - ExtraLesson, - LessonSubstitution, - SupervisionSubstitution, -) -from aleksis.apps.chronos.util.notifications import send_notifications_for_object -from aleksis.core.celery import app - - -@app.task(name="chronos_send_notifications_for_next_day") -def send_notifications_for_next_day(): - """Send notifications for next day.""" - next_day = timezone.now().date() + timezone.timedelta(days=1) - - relevant_objects = [] - relevant_objects += LessonSubstitution.objects.on_day(next_day) - relevant_objects += ExtraLesson.objects.on_day(next_day) - relevant_objects += Event.objects.on_day(next_day) - relevant_objects += SupervisionSubstitution.objects.filter(date=next_day) - - for instance in relevant_objects: - send_notifications_for_object(instance) diff --git a/aleksis/apps/chronos/util/notifications.py b/aleksis/apps/chronos/util/notifications.py index 9cfaea28f2b779e61082fd04fd0a377a264dab92..25216a2e442094e061773800dff98c77f1ab7168 100644 --- a/aleksis/apps/chronos/util/notifications.py +++ b/aleksis/apps/chronos/util/notifications.py @@ -1,3 +1,4 @@ +import zoneinfo from typing import Union from urllib.parse import urljoin @@ -6,8 +7,10 @@ from django.urls import reverse from django.utils.formats import date_format from django.utils.translation import gettext_lazy as _ from django.utils.translation import ngettext - +from django.utils import timezone +from datetime import timedelta, datetime from aleksis.core.models import Notification, Person +from aleksis.core.util.core_helpers import get_site_preferences from ..models import Event, ExtraLesson, LessonSubstitution, SupervisionSubstitution @@ -170,6 +173,30 @@ def send_notifications_for_object( ), ) + dt_start, dt_end = instance.time_range + dt_start = dt_start.replace(tzinfo=zoneinfo.ZoneInfo(settings.TIME_ZONE)) + dt_end = dt_end.replace(tzinfo=zoneinfo.ZoneInfo(settings.TIME_ZONE)) + + send_time = get_site_preferences()["chronos__time_for_sending_notifications"] + number_of_days = get_site_preferences()["chronos__days_in_advance_notifications"] + + start_range = timezone.now().replace(hour=send_time.hour, minute=send_time.minute) + if timezone.now().time() > send_time: + start_range = start_range - timedelta(days=1) + end_range = start_range + timedelta(days=number_of_days) + + if dt_start < start_range and dt_end < end_range: + # Skip this, because the change is in the past + return + + if dt_start <= end_range and dt_end >= start_range: + # Send immediately + send_at = timezone.now() + else: + # Schedule for later + send_at = datetime.combine(dt_start.date() - timedelta(days=number_of_days), send_time).replace(tzinfo=zoneinfo.ZoneInfo(settings.TIME_ZONE)) + + for recipient in recipients: if recipient.preferences["chronos__send_notifications"]: n = Notification( @@ -178,5 +205,6 @@ def send_notifications_for_object( title=_("There are current changes to your timetable."), description=description, link=url, + send_at=send_at ) n.save()