diff --git a/kitsune/notifications/api.py b/kitsune/notifications/api.py index 0f17b7f29d8..a8d76191c68 100644 --- a/kitsune/notifications/api.py +++ b/kitsune/notifications/api.py @@ -1,3 +1,4 @@ +import django_filters from rest_framework import serializers, viewsets, permissions, mixins, status from rest_framework.decorators import action from rest_framework.response import Response @@ -42,6 +43,26 @@ class Meta: ) +class NotificationFilter(django_filters.FilterSet): + is_read = django_filters.MethodFilter(action='filter_is_read') + + class Meta(object): + model = Notification + fields = [ + 'is_read', + ] + + # This has to be a method filter because ``is_read`` is not a database field + # of ``Notification``, so BooleanFilter (and friends) don't work on it. + def filter_is_read(self, queryset, value): + if value in ['1', 'true', 'True', 1, True]: + return queryset.exclude(read_at=None) + elif value in ['0', 'false', 'False', 0, False]: + return queryset.filter(read_at=None) + else: + return queryset + + class NotificationViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): @@ -51,9 +72,12 @@ class NotificationViewSet(mixins.ListModelMixin, permissions.IsAuthenticated, OnlyOwner, ] + filter_class = NotificationFilter + filter_fields = ['is_read'] def get_queryset(self, *args, **kwargs): - return self.model.objects.filter(owner=self.request.user) + qs = super(NotificationViewSet, self).get_queryset(*args, **kwargs) + return qs.filter(owner=self.request.user) @action(methods=['POST']) def mark_read(self, request, pk=None): diff --git a/kitsune/notifications/tests/test_api.py b/kitsune/notifications/tests/test_api.py index f65836880a4..6970bdffba6 100644 --- a/kitsune/notifications/tests/test_api.py +++ b/kitsune/notifications/tests/test_api.py @@ -86,32 +86,51 @@ class TestNotificationViewSet(TestCase): def setUp(self): self.client = APIClient() - follower = profile() - followed = profile() - q = question(creator=followed.user, save=True) + self.follower = profile().user + self.followed = profile().user + self.question = question(creator=self.followed, save=True) # The above might make follows, which this test isn't about. Clear them out. Follow.objects.all().delete() + follow(self.follower, self.followed) - follow(follower.user, followed.user) - - # Make a new action for the above. This should trigger notifications - action.send(followed.user, verb='asked', action_object=q) + def _makeNotification(self, is_read=False): + # Make a new action. This should trigger notifications + action.send(self.followed, verb='asked', action_object=self.question) act = Action.objects.order_by('-id')[0] - self.notification = Notification.objects.get(action=act) + n = Notification.objects.get(action=act) + if is_read: + n.is_read = True + n.save() + return n def test_mark_read(self): - eq_(self.notification.is_read, False) - self.client.force_authenticate(user=self.notification.owner) - req = self.client.post(reverse('notification-mark-read', args=[self.notification.id])) + n = self._makeNotification() + self.client.force_authenticate(user=self.follower) + req = self.client.post(reverse('notification-mark-read', args=[n.id])) eq_(req.status_code, 204) - n = Notification.objects.get(id=self.notification.id) + n = Notification.objects.get(id=n.id) eq_(n.is_read, True) def test_mark_unread(self): - self.notification.is_read = True - self.notification.save() - self.client.force_authenticate(user=self.notification.owner) - req = self.client.post(reverse('notification-mark-unread', args=[self.notification.id])) + n = self._makeNotification(is_read=True) + self.client.force_authenticate(user=self.follower) + req = self.client.post(reverse('notification-mark-unread', args=[n.id])) eq_(req.status_code, 204) - n = Notification.objects.get(id=self.notification.id) + n = Notification.objects.get(id=n.id) eq_(n.is_read, False) + + def test_filter_is_read_false(self): + n = self._makeNotification(is_read=False) + self._makeNotification(is_read=True) + self.client.force_authenticate(user=self.follower) + req = self.client.get(reverse('notification-list') + '?is_read=0') + eq_(req.status_code, 200) + eq_([d['id'] for d in req.data], [n.id]) + + def test_filter_is_read_true(self): + self._makeNotification(is_read=False) + n = self._makeNotification(is_read=True) + self.client.force_authenticate(user=self.follower) + req = self.client.get(reverse('notification-list') + '?is_read=1') + eq_(req.status_code, 200) + eq_([d['id'] for d in req.data], [n.id])