From 8ec167321e512b40f8aa372fefbd1069d6ba7ef3 Mon Sep 17 00:00:00 2001
From: mlbonhomme <bonhomme@teklia.com>
Date: Thu, 9 Mar 2023 12:51:06 +0000
Subject: [PATCH] Add creator_email filter to element listing endpoints

---
 arkindex/documents/api/elements.py            | 10 ++++
 .../documents/tests/test_children_elements.py | 49 +++++++++++++++++++
 .../documents/tests/test_corpus_elements.py   | 47 +++++++++++++++++-
 .../documents/tests/test_parents_elements.py  | 49 +++++++++++++++++++
 4 files changed, 154 insertions(+), 1 deletion(-)

diff --git a/arkindex/documents/api/elements.py b/arkindex/documents/api/elements.py
index aa9215a3ce..fe62bc6b63 100644
--- a/arkindex/documents/api/elements.py
+++ b/arkindex/documents/api/elements.py
@@ -23,6 +23,7 @@ from django.db.models import (
 from django.db.models.functions import Cast
 from django.shortcuts import get_object_or_404
 from django.utils.functional import cached_property
+from drf_spectacular.types import OpenApiTypes
 from drf_spectacular.utils import (
     OpenApiParameter,
     PolymorphicProxySerializer,
@@ -325,6 +326,12 @@ class ElementsListAutoSchema(AutoSchema):
                     type=UUID,
                     required=False,
                 ),
+                OpenApiParameter(
+                    'creator_email',
+                    description='Restrict to elements created by the user with the specified email address.',
+                    type=OpenApiTypes.EMAIL,
+                    required=False,
+                ),
                 OpenApiParameter(
                     'classification_confidence',
                     description='Restrict to elements having a classification with the given confidence. '
@@ -798,6 +805,9 @@ class ElementsListBase(CorpusACLMixin, DestroyModelMixin, ListAPIView):
         if 'name' in self.clean_params:
             filters &= Q(name__icontains=self.clean_params['name'])
 
+        if 'creator_email' in self.clean_params:
+            filters &= Q(creator__email=self.clean_params['creator_email'])
+
         if 'rotation_angle' in self.clean_params:
             try:
                 rotation_angle = int(self.clean_params['rotation_angle'])
diff --git a/arkindex/documents/tests/test_children_elements.py b/arkindex/documents/tests/test_children_elements.py
index 67ed18a55e..784450ed64 100644
--- a/arkindex/documents/tests/test_children_elements.py
+++ b/arkindex/documents/tests/test_children_elements.py
@@ -8,6 +8,7 @@ from arkindex.documents.models import Element, EntityType, MetaType, Transcripti
 from arkindex.process.models import WorkerRun, WorkerVersion
 from arkindex.project.aws import S3FileStatus
 from arkindex.project.tests import FixtureAPITestCase
+from arkindex.users.models import User
 
 
 class TestChildrenElements(FixtureAPITestCase):
@@ -688,6 +689,54 @@ class TestChildrenElements(FixtureAPITestCase):
             ]
         )
 
+    def test_children_filter_creator_email(self):
+        element_type = self.corpus.types.first()
+        user2 = User.objects.get(email='user2@user.fr')
+        test_element = self.corpus.elements.create(type=element_type, name='Test Element', creator=user2)
+        test_element.add_parent(self.vol)
+
+        with self.assertNumQueries(4):
+            response = self.client.get(
+                reverse('api:elements-children', kwargs={'pk': str(self.vol.id)}),
+                data={
+                    'creator_email': 'user2@user.fr'
+                }
+            )
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.json()['results']), 1)
+        self.assertEqual(response.json()['results'][0]['name'], 'Test Element')
+
+    def test_children_filter_creator_email_case_insensitive(self):
+        element_type = self.corpus.types.first()
+        user2 = User.objects.get(email='user2@user.fr')
+        test_element = self.corpus.elements.create(type=element_type, name='Test Element', creator=user2)
+        test_element.add_parent(self.vol)
+
+        with self.assertNumQueries(4):
+            response = self.client.get(
+                reverse('api:elements-children', kwargs={'pk': str(self.vol.id)}),
+                data={
+                    'creator_email': 'USEr2@user.fr'
+                }
+            )
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.json()['results']), 1)
+        self.assertEqual(response.json()['results'][0]['name'], 'Test Element')
+
+    def test_children_filter_creator_email_does_not_exist(self):
+        """
+        If there is no user with the given email, there is no error but no results are returned
+        """
+        with self.assertNumQueries(2):
+            response = self.client.get(
+                reverse('api:elements-children', kwargs={'pk': str(self.vol.id)}),
+                data={
+                    'creator_email': 'ohno@user.fr'
+                }
+            )
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.json()['results']), 0)
+
     def test_children_filter_rotation_angle(self):
         element_type = self.corpus.types.first()
         not_rotated = self.corpus.elements.create(type=element_type, name='not rotated')
diff --git a/arkindex/documents/tests/test_corpus_elements.py b/arkindex/documents/tests/test_corpus_elements.py
index 0102b204f3..00b7b45401 100644
--- a/arkindex/documents/tests/test_corpus_elements.py
+++ b/arkindex/documents/tests/test_corpus_elements.py
@@ -5,9 +5,10 @@ import sqlparse
 from django.urls import reverse
 from rest_framework import status
 
-from arkindex.documents.models import Corpus, Element, EntityType, MetaData, MetaType, Transcription
+from arkindex.documents.models import Corpus, Element, ElementType, EntityType, MetaData, MetaType, Transcription
 from arkindex.process.models import WorkerVersion
 from arkindex.project.tests import FixtureAPITestCase
+from arkindex.users.models import User
 
 
 class TestListElements(FixtureAPITestCase):
@@ -136,6 +137,50 @@ class TestListElements(FixtureAPITestCase):
         for result in results:
             self.assertIn(nameSelected, result['name'])
 
+    def test_list_elements_filter_creator_email(self):
+        page_type = ElementType.objects.get(corpus=self.corpus, slug='page')
+        user2 = User.objects.get(email='user2@user.fr')
+        self.corpus.elements.create(type=page_type, name='Test Element', creator=user2)
+        mail = 'user2@user.fr'
+        with self.assertNumQueries(4):
+            response = self.client.get(
+                reverse('api:corpus-elements', kwargs={'corpus': self.corpus.id}),
+                data={'creator_email': mail}
+            )
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        results = response.json()['results']
+        self.assertEqual(len(results), 1)
+        self.assertEqual(results[0]['name'], 'Test Element')
+
+    def test_list_elements_filter_creator_email_case_insensitive(self):
+        page_type = ElementType.objects.get(corpus=self.corpus, slug='page')
+        user2 = User.objects.get(email='user2@user.fr')
+        self.corpus.elements.create(type=page_type, name='Test Element', creator=user2)
+        mail = 'UsER2@user.fr'
+        with self.assertNumQueries(4):
+            response = self.client.get(
+                reverse('api:corpus-elements', kwargs={'corpus': self.corpus.id}),
+                data={'creator_email': mail}
+            )
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        results = response.json()['results']
+        self.assertEqual(len(results), 1)
+        self.assertEqual(results[0]['name'], 'Test Element')
+
+    def test_list_elements_filter_creator_email_does_not_exist(self):
+        """
+        If there is no user with the given email, there is no error but no results are returned
+        """
+        mail = 'ohno@user.fr'
+        with self.assertNumQueries(2):
+            response = self.client.get(
+                reverse('api:corpus-elements', kwargs={'corpus': self.corpus.id}),
+                data={'creator_email': mail}
+            )
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        results = response.json()['results']
+        self.assertEqual(len(results), 0)
+
     def test_list_elements_corpus_uuid4(self):
         """
         Ensure the corpus filter allows any UUID, not just version 4 UUIDs.
diff --git a/arkindex/documents/tests/test_parents_elements.py b/arkindex/documents/tests/test_parents_elements.py
index f07e4a0119..96d2e98a1c 100644
--- a/arkindex/documents/tests/test_parents_elements.py
+++ b/arkindex/documents/tests/test_parents_elements.py
@@ -7,6 +7,7 @@ from rest_framework import status
 from arkindex.documents.models import Corpus, Element, EntityType, MetaType
 from arkindex.process.models import WorkerVersion
 from arkindex.project.tests import FixtureAPITestCase
+from arkindex.users.models import User
 
 
 class TestParentsElements(FixtureAPITestCase):
@@ -397,6 +398,54 @@ class TestParentsElements(FixtureAPITestCase):
                     expected_elements
                 )
 
+    def test_parents_filter_creator_email(self):
+        element_type = self.corpus.types.first()
+        user2 = User.objects.get(email='user2@user.fr')
+        parent_element = self.corpus.elements.create(type=element_type, name='Test Element', creator=user2)
+        self.page.add_parent(parent_element)
+
+        with self.assertNumQueries(4):
+            response = self.client.get(
+                reverse('api:elements-parents', kwargs={'pk': str(self.page.id)}),
+                data={
+                    'creator_email': 'user2@user.fr'
+                }
+            )
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.json()['results']), 1)
+        self.assertEqual(response.json()['results'][0]['name'], 'Test Element')
+
+    def test_parents_filter_creator_email_case_insensitive(self):
+        element_type = self.corpus.types.first()
+        user2 = User.objects.get(email='user2@user.fr')
+        parent_element = self.corpus.elements.create(type=element_type, name='Test Element', creator=user2)
+        self.page.add_parent(parent_element)
+
+        with self.assertNumQueries(4):
+            response = self.client.get(
+                reverse('api:elements-parents', kwargs={'pk': str(self.page.id)}),
+                data={
+                    'creator_email': 'USEr2@user.fr'
+                }
+            )
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.json()['results']), 1)
+        self.assertEqual(response.json()['results'][0]['name'], 'Test Element')
+
+    def test_parents_filter_creator_email_does_not_exist(self):
+        """
+        If there is no user with the given email, there is no error but no results are returned
+        """
+        with self.assertNumQueries(2):
+            response = self.client.get(
+                reverse('api:elements-parents', kwargs={'pk': str(self.page.id)}),
+                data={
+                    'creator_email': 'ohno@user.fr'
+                }
+            )
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+        self.assertEqual(len(response.json()['results']), 0)
+
     def test_parents_invalid_order(self):
         cases = [
             ({'order': 'blah', 'order_direction': 'asc'}, {'order': ['Unknown sorting field']}),
-- 
GitLab