From 71860ba985f86f38eb4a9eb477183f7e87d07d6e Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 4 Jul 2024 15:05:48 -0400 Subject: [PATCH] Enable event rules to target notification groups --- netbox/extras/events.py | 27 ++++++++++++++------------- netbox/extras/models/notifications.py | 19 +++++++++++++++++++ netbox/extras/signals.py | 10 +++++----- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/netbox/extras/events.py b/netbox/extras/events.py index cf76b3564..c34055ac4 100644 --- a/netbox/extras/events.py +++ b/netbox/extras/events.py @@ -18,18 +18,15 @@ from utilities.api import get_serializer_for_model from utilities.rqworker import get_rq_retry from utilities.serialization import serialize_object from .choices import EventRuleActionChoices +from .constants import EVENT_CREATE, EVENT_DELETE, EVENT_UPDATE from .models import EventRule logger = logging.getLogger('netbox.events_processor') -EVENT_OBJECT_CREATED = 'object_created' -EVENT_OBJECT_UPDATED = 'object_updated' -EVENT_OBJECT_DELETED = 'object_deleted' - # Register event types -Event(name=EVENT_OBJECT_CREATED, text=_('Object created')).register() -Event(name=EVENT_OBJECT_UPDATED, text=_('Object updated')).register() -Event(name=EVENT_OBJECT_DELETED, text=_('Object deleted')).register() +Event(name=EVENT_CREATE, text=_('Object created')).register() +Event(name=EVENT_UPDATE, text=_('Object updated')).register() +Event(name=EVENT_DELETE, text=_('Object deleted')).register() def serialize_for_event(instance): @@ -88,7 +85,7 @@ def enqueue_object(queue, instance, user, request_id, action): } -def process_event_rules(event_rules, model_name, event, data, username=None, snapshots=None, request_id=None): +def process_event_rules(event_rules, object_type, event, data, username=None, snapshots=None, request_id=None): if username: user = get_user_model().objects.get(username=username) else: @@ -110,7 +107,7 @@ def process_event_rules(event_rules, model_name, event, data, username=None, sna # Compile the task parameters params = { "event_rule": event_rule, - "model_name": model_name, + "model_name": object_type.model, "event": event, "data": data, "snapshots": snapshots, @@ -143,10 +140,14 @@ def process_event_rules(event_rules, model_name, event, data, username=None, sna data=data ) - # Notifications + # Notification groups elif event_rule.action_type == EventRuleActionChoices.NOTIFICATION: - # TODO: Create notifications - pass + # Bulk-create notifications for all members of the notification group + event_rule.action_object.notify( + object_type=object_type, + object_id=data['id'], + event_name=event + ) else: raise ValueError(_("Unknown action type for an event rule: {action_type}").format( @@ -182,7 +183,7 @@ def process_event_queue(events): event_rules = events_cache[action_flag][content_type] process_event_rules( - event_rules, content_type.model, data['event'], data['data'], data['username'], + event_rules, content_type, data['event'], data['data'], data['username'], snapshots=data['snapshots'], request_id=data['request_id'] ) diff --git a/netbox/extras/models/notifications.py b/netbox/extras/models/notifications.py index 33fda8b9b..650b3cf90 100644 --- a/netbox/extras/models/notifications.py +++ b/netbox/extras/models/notifications.py @@ -11,6 +11,7 @@ from core.models import ObjectType from extras.querysets import NotificationQuerySet from netbox.models import ChangeLoggedModel from netbox.registry import registry +from users.models import User from utilities.querysets import RestrictedQuerySet __all__ = ( @@ -135,6 +136,24 @@ class NotificationGroup(ChangeLoggedModel): def get_absolute_url(self): return reverse('extras:notificationgroup', args=[self.pk]) + @cached_property + def members(self): + """ + Return all Users who belong to this notification group. + """ + return self.users.union( + User.objects.filter(groups__in=self.groups.all()) + ).order_by('username') + + def notify(self, **kwargs): + """ + Bulk-create Notifications for all members of this group. + """ + Notification.objects.bulk_create([ + Notification(user=member, **kwargs) + for member in self.members + ]) + class Subscription(models.Model): """ diff --git a/netbox/extras/signals.py b/netbox/extras/signals.py index c6895bec5..a07cae7ea 100644 --- a/netbox/extras/signals.py +++ b/netbox/extras/signals.py @@ -12,7 +12,7 @@ from django_prometheus.models import model_deletes, model_inserts, model_updates from core.choices import ObjectChangeActionChoices from core.models import ObjectChange, ObjectType from core.signals import job_end, job_start -from extras.constants import EVENT_JOB_END, EVENT_JOB_START +from extras.constants import EVENT_JOB_END, EVENT_JOB_START, EVENT_UPDATE from extras.events import process_event_rules from extras.models import EventRule, Notification, Subscription from netbox.config import get_config @@ -21,7 +21,7 @@ from netbox.models.features import ChangeLoggingMixin from netbox.registry import registry from netbox.signals import post_clean from utilities.exceptions import AbortRequest -from .events import EVENT_OBJECT_UPDATED, enqueue_object +from .events import enqueue_object from .models import CustomField, TaggedItem from .validators import CustomValidator @@ -271,7 +271,7 @@ def process_job_start_event_rules(sender, **kwargs): """ event_rules = EventRule.objects.filter(type_job_start=True, enabled=True, object_types=sender.object_type) username = sender.user.username if sender.user else None - process_event_rules(event_rules, sender.object_type.model, EVENT_JOB_START, sender.data, username) + process_event_rules(event_rules, sender.object_type, EVENT_JOB_START, sender.data, username) @receiver(job_end) @@ -281,7 +281,7 @@ def process_job_end_event_rules(sender, **kwargs): """ event_rules = EventRule.objects.filter(type_job_end=True, enabled=True, object_types=sender.object_type) username = sender.user.username if sender.user else None - process_event_rules(event_rules, sender.object_type.model, EVENT_JOB_END, sender.data, username) + process_event_rules(event_rules, sender.object_type, EVENT_JOB_END, sender.data, username) # @@ -309,7 +309,7 @@ def notify_object_changed(sender, instance, created, raw, **kwargs): Notification( user_id=sub['user'], object=instance, - event_name=EVENT_OBJECT_UPDATED + event_name=EVENT_UPDATE ) for sub in subscriptions ]