From b5c159bf63ec12cff3e6101fac0ce83c2cbac5be Mon Sep 17 00:00:00 2001 From: Samuel Paccoud - DINUM Date: Fri, 15 Nov 2024 09:42:27 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8(backend)=20allow=20filtering=20on=20d?= =?UTF-8?q?ocument=20titles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the minimal and fast search feature, while we are working on a full text search based on opensearch. For the moment we only search on the title of the document. --- src/backend/core/api/filters.py | 5 ++- src/backend/core/api/viewsets.py | 3 +- .../documents/test_api_documents_list.py | 44 +++++++++++++++++++ .../documents/test_api_documents_retrieve.py | 2 +- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/backend/core/api/filters.py b/src/backend/core/api/filters.py index 18092d92..fbf8229a 100644 --- a/src/backend/core/api/filters.py +++ b/src/backend/core/api/filters.py @@ -18,10 +18,13 @@ class DocumentFilter(django_filters.FilterSet): is_favorite = django_filters.BooleanFilter( method="filter_is_favorite", label=_("Favorite") ) + title = django_filters.CharFilter( + field_name="title", lookup_expr="icontains", label=_("Title") + ) class Meta: model = models.Document - fields = ["is_creator_me", "is_favorite", "link_reach"] + fields = ["is_creator_me", "is_favorite", "link_reach", "title"] # pylint: disable=unused-argument def filter_is_creator_me(self, queryset, name, value): diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index be605381..75c0f5c4 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -326,10 +326,11 @@ class DocumentViewSet( - `is_creator_me=false`: Returns documents created by other users. - `is_favorite=true`: Returns documents marked as favorite by the current user - `is_favorite=false`: Returns documents not marked as favorite by the current user + - `title=hello`: Returns documents which title contains the "hello" string Example Usage: - GET /api/v1.0/documents/?is_creator_me=true&is_favorite=true - - GET /api/v1.0/documents/?is_creator_me=false + - GET /api/v1.0/documents/?is_creator_me=false&title=hello """ filter_backends = [filters.DjangoFilterBackend, drf_filters.OrderingFilter] diff --git a/src/backend/core/tests/documents/test_api_documents_list.py b/src/backend/core/tests/documents/test_api_documents_list.py index 20cef11f..4089385e 100644 --- a/src/backend/core/tests/documents/test_api_documents_list.py +++ b/src/backend/core/tests/documents/test_api_documents_list.py @@ -433,6 +433,7 @@ def test_api_documents_list_filter_is_creator_me_invalid(): results = response.json()["results"] assert len(results) == 5 + # Filters: is_favorite @@ -495,6 +496,7 @@ def test_api_documents_list_filter_is_favorite_invalid(): results = response.json()["results"] assert len(results) == 5 + # Filters: link_reach @@ -534,3 +536,45 @@ def test_api_documents_list_filter_link_reach_invalid(): ] } + +# Filters: title + + +@pytest.mark.parametrize( + "query,nb_results", + [ + ("Project Alpha", 1), # Exact match + ("project", 2), # Partial match (case-insensitive) + ("Guide", 1), # Word match within a title + ("Special", 0), # No match (nonexistent keyword) + ("2024", 2), # Match by numeric keyword + ("", 5), # Empty string + ], +) +def test_api_documents_list_filter_title(query, nb_results): + """Authenticated users should be able to search documents by their title.""" + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + # Create documents with predefined titles + titles = [ + "Project Alpha Documentation", + "Project Beta Overview", + "User Guide", + "Financial Report 2024", + "Annual Review 2024", + ] + for title in titles: + factories.DocumentFactory(title=title, users=[user]) + + # Perform the search query + response = client.get(f"/api/v1.0/documents/?title={query:s}") + + assert response.status_code == 200 + results = response.json()["results"] + assert len(results) == nb_results + + # Ensure all results contain the query in their title + for result in results: + assert query.lower().strip() in result["title"].lower() diff --git a/src/backend/core/tests/documents/test_api_documents_retrieve.py b/src/backend/core/tests/documents/test_api_documents_retrieve.py index 4ff18918..3368395d 100644 --- a/src/backend/core/tests/documents/test_api_documents_retrieve.py +++ b/src/backend/core/tests/documents/test_api_documents_retrieve.py @@ -44,8 +44,8 @@ def test_api_documents_retrieve_anonymous_public(): "is_favorite": False, "link_reach": "public", "link_role": document.link_role, - "title": document.title, "nb_accesses": 0, + "title": document.title, "updated_at": document.updated_at.isoformat().replace("+00:00", "Z"), }