Skip to content

Commit

Permalink
Send notifications via django-q2
Browse files Browse the repository at this point in the history
  • Loading branch information
hmpf committed Apr 25, 2023
1 parent f50b2f8 commit 6678b2a
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 28 deletions.
5 changes: 2 additions & 3 deletions src/argus/incident/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ 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")
post_delete.connect(delete_associated_event, "argus_incident.Acknowledgement")
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")
31 changes: 21 additions & 10 deletions src/argus/incident/signals.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
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",
"delete_associated_event",
"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:
Expand All @@ -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()
Expand Down
21 changes: 17 additions & 4 deletions src/argus/notificationprofile/media/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@


__all__ = [
"are_notifications_turned_on",
"send_notification",
"background_send_notification",
"find_destinations_for_event",
Expand All @@ -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


Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/argus/notificationprofile/media/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 3 additions & 2 deletions src/argus/notificationprofile/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -169,7 +170,7 @@ class Meta:

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filter_wrapper = FilterWrapper(self.filter)
self.filter_wrapper = FilterWrapper(self.filter, self.user)

def __str__(self):
return f"{self.name} [{self.filter_string}]"
Expand Down
15 changes: 6 additions & 9 deletions src/argus/util/testing.py
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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

0 comments on commit 6678b2a

Please sign in to comment.