From 92aa7adfecd1d7c4492dc1feb5de9900971a9aba Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 6 Jun 2022 15:21:31 +1000 Subject: [PATCH] Adds callback for creation of an error log (#3136) * Adds callback for creation of an error log * Fix unit tests --- InvenTree/InvenTree/models.py | 40 +++++++++++++++++++++++++- InvenTree/common/notifications.py | 5 ++-- InvenTree/common/test_notifications.py | 4 +-- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/InvenTree/InvenTree/models.py b/InvenTree/InvenTree/models.py index 2a089685ef..90d8a0314b 100644 --- a/InvenTree/InvenTree/models.py +++ b/InvenTree/InvenTree/models.py @@ -5,17 +5,21 @@ import os import re from django.conf import settings +from django.contrib.auth import get_user_model from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.db import models -from django.db.models.signals import pre_delete +from django.db.models.signals import post_save, pre_delete from django.dispatch import receiver +from django.urls import reverse from django.utils.translation import gettext_lazy as _ +from error_report.models import Error from mptt.exceptions import InvalidMove from mptt.models import MPTTModel, TreeForeignKey +import InvenTree.helpers from InvenTree.fields import InvenTreeURLField from InvenTree.validators import validate_tree_name @@ -442,3 +446,37 @@ def before_delete_tree_item(sender, instance, using, **kwargs): for child in instance.children.all(): child.parent = instance.parent child.save() + + +@receiver(post_save, sender=Error, dispatch_uid='error_post_save_notification') +def after_error_logged(sender, instance: Error, created: bool, **kwargs): + """Callback when a server error is logged. + + - Send a UI notification to all users with staff status + """ + + if created: + try: + import common.notifications + + users = get_user_model().objects.filter(is_staff=True) + + context = { + 'error': instance, + 'name': _('Server Error'), + 'message': _('An error has been logged by the server.'), + 'link': InvenTree.helpers.construct_absolute_url( + reverse('admin:error_report_error_change', kwargs={'object_id': instance.pk}) + ) + } + + common.notifications.trigger_notification( + instance, + 'inventree.error_log', + context=context, + targets=users, + ) + + except Exception as exc: + """We do not want to throw an exception while reporting an exception""" + logger.error(exc) diff --git a/InvenTree/common/notifications.py b/InvenTree/common/notifications.py index 122d7deaeb..4003276763 100644 --- a/InvenTree/common/notifications.py +++ b/InvenTree/common/notifications.py @@ -299,11 +299,12 @@ def trigger_notification(obj, category=None, obj_ref='pk', **kwargs): delivery_methods = (delivery_methods - IGNORED_NOTIFICATION_CLS) for method in delivery_methods: - logger.info(f"Triggering method '{method.METHOD_NAME}'") + logger.info(f"Triggering notification method '{method.METHOD_NAME}'") try: deliver_notification(method, obj, category, targets, context) except NotImplementedError as error: - raise error + # Allow any single notification method to fail, without failing the others + logger.error(error) except Exception as error: logger.error(error) diff --git a/InvenTree/common/test_notifications.py b/InvenTree/common/test_notifications.py index ab4b0838fd..08095a598b 100644 --- a/InvenTree/common/test_notifications.py +++ b/InvenTree/common/test_notifications.py @@ -93,7 +93,7 @@ class BulkNotificationMethodTests(BaseNotificationIntegrationTest): def get_targets(self): return [1, ] - with self.assertRaises(NotImplementedError): + with self.assertLogs(logger='inventree', level='ERROR'): self._notification_run(WrongImplementation) @@ -115,7 +115,7 @@ class SingleNotificationMethodTests(BaseNotificationIntegrationTest): def get_targets(self): return [1, ] - with self.assertRaises(NotImplementedError): + with self.assertLogs(logger='inventree', level='ERROR'): self._notification_run(WrongImplementation) # A integration test for notifications is provided in test_part.PartNotificationTest