2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-02 03:30:54 +00:00

Adding bulk deletion endpoint for notifications (#3154)

* Catch DoesNotExist error

* Move notificationtable function to js file

* Fix for custom metadata class

- Previously only worked if a POST or PUT action was available on the endpoint
- So, a ListAPIView endpoint would not actually work!
- Adding in a BulkDelete mixin to a ListAPIView caused failure

* Add unit test to ensure new OPTIONS metadata updates are checked

* Expand functionality of the existing BulkDelete mixin

- Allow deletion by custom filters
- Allow each implementing class to implement custom filters
- Adds more unit testing for BulkDelete mixin class

* Add bulk delete operation for Notification API

- Ensure users can only delete their *own* notifications

* Improve notification tables / buttons / etc

* Adds unit testing for bulk delete of notifications

- Fixed API permissions for notifications list endpoint

* Update BulkDelete operations for the StockItemTestResult table

* Use filters parameter in attachments table to ensure that only correct attachments are deleted

* JS linting

* Fixes for unit tests
This commit is contained in:
Oliver
2022-06-08 07:45:30 +10:00
committed by GitHub
parent c0148c0a38
commit 403655e3d2
17 changed files with 379 additions and 132 deletions

View File

@ -16,6 +16,7 @@ from rest_framework.views import APIView
import common.models
import common.serializers
from InvenTree.api import BulkDeleteMixin
from InvenTree.helpers import inheritors
from plugin.models import NotificationUserSetting
from plugin.serializers import NotificationUserSettingSerializer
@ -258,12 +259,16 @@ class NotificationUserSettingsDetail(generics.RetrieveUpdateAPIView):
]
class NotificationList(generics.ListAPIView):
class NotificationList(BulkDeleteMixin, generics.ListAPIView):
"""List view for all notifications of the current user."""
queryset = common.models.NotificationMessage.objects.all()
serializer_class = common.serializers.NotificationMessageSerializer
permission_classes = [
permissions.IsAuthenticated,
]
filter_backends = [
DjangoFilterBackend,
filters.SearchFilter,
@ -298,6 +303,12 @@ class NotificationList(generics.ListAPIView):
queryset = queryset.filter(user=user)
return queryset
def filter_delete_queryset(self, queryset, request):
"""Ensure that the user can only delete their *own* notifications"""
queryset = queryset.filter(user=request.user)
return queryset
class NotificationDetail(generics.RetrieveUpdateDestroyAPIView):
"""Detail view for an individual notification object.

View File

@ -14,7 +14,8 @@ from plugin.models import NotificationUserSetting, PluginConfig
from .api import WebhookView
from .models import (ColorTheme, InvenTreeSetting, InvenTreeUserSetting,
NotificationEntry, WebhookEndpoint, WebhookMessage)
NotificationEntry, NotificationMessage, WebhookEndpoint,
WebhookMessage)
CONTENT_TYPE_JSON = 'application/json'
@ -665,6 +666,10 @@ class WebhookMessageTests(TestCase):
class NotificationTest(InvenTreeAPITestCase):
"""Tests for NotificationEntriy."""
fixtures = [
'users',
]
def test_check_notification_entries(self):
"""Test that notification entries can be created."""
# Create some notification entries
@ -684,9 +689,84 @@ class NotificationTest(InvenTreeAPITestCase):
def test_api_list(self):
"""Test list URL."""
url = reverse('api-notifications-list')
self.get(url, expected_code=200)
# Test the OPTIONS endpoint for the 'api-notification-list'
# Ref: https://github.com/inventree/InvenTree/pull/3154
response = self.options(url)
self.assertIn('DELETE', response.data['actions'])
self.assertIn('GET', response.data['actions'])
self.assertNotIn('POST', response.data['actions'])
self.assertEqual(response.data['description'], 'List view for all notifications of the current user.')
# POST action should fail (not allowed)
response = self.post(url, {}, expected_code=405)
def test_bulk_delete(self):
"""Tests for bulk deletion of user notifications"""
from error_report.models import Error
# Create some notification messages by throwing errors
for _ii in range(10):
Error.objects.create()
# Check that messsages have been created
messages = NotificationMessage.objects.all()
# As there are three staff users (including the 'test' user) we expect 30 notifications
self.assertEqual(messages.count(), 30)
# Only 10 messages related to *this* user
my_notifications = messages.filter(user=self.user)
self.assertEqual(my_notifications.count(), 10)
# Get notification via the API
url = reverse('api-notifications-list')
response = self.get(url, {}, expected_code=200)
self.assertEqual(len(response.data), 10)
# Mark some as read
for ntf in my_notifications[0:3]:
ntf.read = True
ntf.save()
# Read out via API again
response = self.get(
url,
{
'read': True,
},
expected_code=200
)
# Check validity of returned data
self.assertEqual(len(response.data), 3)
for ntf in response.data:
self.assertTrue(ntf['read'])
# Now, let's bulk delete all 'unread' notifications via the API,
# but only associated with the logged in user
response = self.delete(
url,
{
'filters': {
'read': False,
}
},
expected_code=204,
)
# Only 7 notifications should have been deleted,
# as the notifications associated with other users must remain untouched
self.assertEqual(NotificationMessage.objects.count(), 23)
self.assertEqual(NotificationMessage.objects.filter(user=self.user).count(), 3)
class LoadingTest(TestCase):
"""Tests for the common config."""