From b39d1860e08807a7c577c9bd49a113bc0799be97 Mon Sep 17 00:00:00 2001 From: Hanne Moa Date: Tue, 25 Apr 2023 09:18:23 +0200 Subject: [PATCH] Send notifications via django-q2 --- src/argus/incident/apps.py | 5 ++- src/argus/incident/signals.py | 31 +++++++++++++------ .../notificationprofile/media/__init__.py | 21 ++++++++++--- src/argus/notificationprofile/media/email.py | 1 + src/argus/notificationprofile/models.py | 6 ++-- src/argus/util/testing.py | 15 ++++----- 6 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/argus/incident/apps.py b/src/argus/incident/apps.py index d0af056c1..ad7ff24d9 100644 --- a/src/argus/incident/apps.py +++ b/src/argus/incident/apps.py @@ -12,8 +12,7 @@ def ready(self): create_first_event, delete_associated_user, delete_associated_event, - task_send_notification, # noqa - task_background_send_notification, + enqueue_event_for_notification, ) post_delete.connect(delete_associated_user, "argus_incident.SourceSystem") @@ -21,4 +20,4 @@ def ready(self): post_delete.connect(close_token_incident, "authtoken.Token") post_save.connect(close_token_incident, "authtoken.Token") post_save.connect(create_first_event, "argus_incident.Incident") - post_save.connect(task_background_send_notification, "argus_incident.Event", dispatch_uid="send_notification") + post_save.connect(enqueue_event_for_notification, "argus_incident.Event", dispatch_uid="send_notification") diff --git a/src/argus/incident/signals.py b/src/argus/incident/signals.py index 92d03a672..fcf305c40 100644 --- a/src/argus/incident/signals.py +++ b/src/argus/incident/signals.py @@ -1,15 +1,20 @@ +import logging + from django.db.models import Q from django.utils import timezone + from rest_framework.authtoken.models import Token +from django_q.tasks import async_task from argus.incident.models import get_or_create_default_instances, Incident -from argus.notificationprofile.media import send_notifications_to_users -from argus.notificationprofile.media import background_send_notification +from argus.notificationprofile.media import find_destinations_for_event from argus.notificationprofile.media import send_notification +from argus.notificationprofile.media import are_notifications_turned_on from .models import Acknowledgement, ChangeEvent, Event, Incident, SourceSystem, Tag __all__ = [ + "enqueue_event_for_notification", "delete_associated_user", "create_first_event", "send_notification", @@ -17,6 +22,20 @@ "close_token_incident", ] +LOG = logging.getLogger(__name__) + + +def enqueue_event_for_notification(sender, instance: Event, *args, **kwargs): + if not are_notifications_turned_on(): + return + + destinations = find_destinations_for_event(instance) + if destinations: + LOG.info('Notification: will be sending notification for "%s"', instance) + async_task(send_notification, destinations, instance, group='notifications') + else: + LOG.debug('Notification: no destinations to send notification to') + def delete_associated_user(sender, instance: SourceSystem, *args, **kwargs): if hasattr(instance, "user") and instance.user: @@ -37,14 +56,6 @@ def create_first_event(sender, instance: Incident, created, raw, *args, **kwargs ) -def task_send_notification(sender, instance: Event, *args, **kwargs): - send_notifications_to_users(instance) - - -def task_background_send_notification(sender, instance: Event, *args, **kwargs): - send_notifications_to_users(instance, background_send_notification) - - def delete_associated_event(sender, instance: Acknowledgement, *args, **kwargs): if hasattr(instance, "event") and instance.event: instance.event.delete() diff --git a/src/argus/notificationprofile/media/__init__.py b/src/argus/notificationprofile/media/__init__.py index ff005f496..26b6a8cad 100644 --- a/src/argus/notificationprofile/media/__init__.py +++ b/src/argus/notificationprofile/media/__init__.py @@ -22,6 +22,7 @@ __all__ = [ + "are_notifications_turned_on", "send_notification", "background_send_notification", "find_destinations_for_event", @@ -36,16 +37,27 @@ MEDIA_CLASSES_DICT = {media_class.MEDIA_SLUG: media_class for media_class in MEDIA_CLASSES} +def are_notifications_turned_on(): + if not getattr(settings, "SEND_NOTIFICATIONS", False): + LOG.info("Notification: turned off sitewide, not sending any") + return False + return True + + def send_notification(destinations: List[DestinationConfig], event: Event): sent = False media = get_notification_media(destinations) + if not media: + LOG.debug("Notification: No media to send to") + return # Plugin expects queryset... ids = (dest.id for dest in destinations) qs = DestinationConfig.objects.filter(id__in=ids) for medium in media: sent = medium.send(event, qs) or sent + LOG.debug('Notification: Sent "%s" to "%s"', event, medium) if not sent: - LOG.warn("Notification: Could not send notification, nowhere to send it to") + LOG.debug("Notification: Could not send notification, nowhere to send it to") # TODO Store error as incident @@ -65,13 +77,14 @@ def find_destinations_for_event(event: Event): if profile.incident_fits(incident) and profile.event_fits(event): destinations.extend(profile.destinations.all()) if not destinations: - LOG.info('Notification: no listeners for "%s"', event) + LOG.debug('Notification: no listeners for "%s"', event) + else: + LOG.debug('Notification: found destinations for %s: %s', event, destinations) return destinations def send_notifications_to_users(event: Event, send=send_notification): - if not getattr(settings, "SEND_NOTIFICATIONS", False): - LOG.info('Notification: turned off sitewide, not sending for "%s"', event) + if not are_notifications_turned_on(): return # TODO: only send one notification per medium per user LOG.info('Notification: sending event "%s"', event) diff --git a/src/argus/notificationprofile/media/email.py b/src/argus/notificationprofile/media/email.py index 4c58e1055..c44766437 100644 --- a/src/argus/notificationprofile/media/email.py +++ b/src/argus/notificationprofile/media/email.py @@ -174,5 +174,6 @@ def send(event: Event, destinations: QuerySet[DestinationConfig], **_) -> bool: recipient_list=recipient_list, html_message=html_message, ) + LOG.debug('Notification: email: sent "%s"', event) return True diff --git a/src/argus/notificationprofile/models.py b/src/argus/notificationprofile/models.py index 9bc902f06..5d3a3c0be 100644 --- a/src/argus/notificationprofile/models.py +++ b/src/argus/notificationprofile/models.py @@ -97,9 +97,10 @@ def save(self, *args, **kwargs): class FilterWrapper: TRINARY_FILTERS = ("open", "acked", "stateful") - def __init__(self, filterblob): + def __init__(self, filterblob, user=None): self.fallback_filter = getattr(settings, "ARGUS_FALLBACK_FILTER", {}) self.filter = filterblob + self.user = user # simplifies debugging, set breakpoint for specific user def _get_tristate(self, tristate): fallback_filter = self.fallback_filter.get(tristate, None) @@ -169,7 +170,8 @@ class Meta: def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.filter_wrapper = FilterWrapper(self.filter) + user = getattr(self, 'user', None) + self.filter_wrapper = FilterWrapper(self.filter, user) def __str__(self): return f"{self.name} [{self.filter_string}]" diff --git a/src/argus/util/testing.py b/src/argus/util/testing.py index 12eb6488d..ff4f71995 100644 --- a/src/argus/util/testing.py +++ b/src/argus/util/testing.py @@ -1,9 +1,6 @@ -from django.db.models.signals import post_save - -from argus.incident.signals import send_notification -from argus.incident.signals import background_send_notification -from argus.incident.models import Event +# import the signal sender (aka. post_save) +# import the signal receivers __all__ = [ "disconnect_signals", @@ -15,10 +12,10 @@ def disconnect_signals(): - post_save.disconnect(send_notification, Event, dispatch_uid="send_notification") - post_save.disconnect(background_send_notification, Event, dispatch_uid="send_notification") + # signal.disconnect(receiver) + pass def connect_signals(): - post_save.connect(send_notification, Event, dispatch_uid="send_notification") - post_save.connect(background_send_notification, Event, dispatch_uid="send_notification") + # signal.connect(receiver) + pass