Repository: zestedesavoir/zds-site

Issue:
API: filtrer les notifications par `is_read`
**Description du besoin**

Pour les besoins de l'extension, il serait intéressant de pouvoir filtrer les notifications (URL `/api/notifications`) selon leur propriété `is_read` pour ne récupérer que les non lues (les autres n'ayant pas d'intérêt pour ce cas d'usage).

**Description de la solution**

Ajouter un filtre pour `is_read` (booléen) sur l'URL `/api/notifications`

**Description des alternatives**

Pouvoir trier selon cette propriété (pour avoir les non-lues d'abord), _a minima_.

**Contexte additionnel**

Voir le code de [notifier.js#64](https://github.com/zestedesavoir/extensions-notificateurs/blob/master/Universal/notifier.js#L64) pour voir le cas d'usage en question (qui me permettrait de supprimer le `.filter()` ligne 78 tout en récupérant des notifications potentiellement anciennes mais non lues qui sont actuellement inaccessibles).



Discussion:

Resolving patch:
diff --git a/zds/notification/api/views.py b/zds/notification/api/views.py
--- a/zds/notification/api/views.py
+++ b/zds/notification/api/views.py
@@ -84,6 +84,9 @@ def get(self, request, *args, **kwargs):
             - name: subscription_type
               description: Filters by subscription type.
               paramType: query
+            - name: is_read
+              description: Filters by read status.
+              paramType: query
             - name: expand
               description: Returns an object instead of an identifier representing the given field.
               required: false
@@ -104,4 +107,9 @@ def get_queryset(self):
         _type = self.request.query_params.get("type", None)
         if _type:
             queryset = queryset.filter(content_type__model=_type)
+        is_read = str(self.request.query_params.get("is_read", None)).lower()
+        if is_read == "true":
+            queryset = queryset.filter(is_read=True)
+        elif is_read == "false":
+            queryset = queryset.filter(is_read=False)
         return queryset


Test patch:
diff --git a/zds/notification/api/tests.py b/zds/notification/api/tests.py
--- a/zds/notification/api/tests.py
+++ b/zds/notification/api/tests.py
@@ -103,3 +103,43 @@ def create_notification_for_pm(self, sender, target):
         topic.add_participant(target, silent=True)
         send_message_mp(author=sender, n_topic=topic, text="Testing")
         return topic
+
+    def test_filter_read_notifications(self):
+        """
+        Filter notification list according to their read status.
+        """
+        # Create a notification (not read yet):
+        topic = self.create_notification_for_pm(ProfileFactory().user, self.profile.user)
+
+        # Get unread notifications:
+        response = self.client.get(reverse("api:notification:list") + "?is_read=false")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data.get("count"), 1)
+
+        # Get read notifications:
+        response = self.client.get(reverse("api:notification:list") + "?is_read=true")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data.get("count"), 0)
+
+        # Read the notification:
+        notification = Notification.objects.get(object_id=topic.last_message.pk, is_read=False)
+        notification.is_read = True
+        notification.save()
+
+        # Get unread notifications:
+        response = self.client.get(reverse("api:notification:list") + "?is_read=false")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data.get("count"), 0)
+
+        # Get read notifications:
+        response = self.client.get(reverse("api:notification:list") + "?is_read=true")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data.get("count"), 1)
+
+        # Create a new notification (not read yet):
+        self.create_notification_for_pm(ProfileFactory().user, self.profile.user)
+
+        # Wrong values are ignored:
+        response = self.client.get(reverse("api:notification:list") + "?is_read=foo")
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(response.data.get("count"), 2)