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:
@ -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.
|
||||
|
@ -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."""
|
||||
|
Reference in New Issue
Block a user