diff --git a/src/backend/core/api/filters.py b/src/backend/core/api/filters.py index 18092d92b..fbf8229a7 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 be605381d..75c0f5c4c 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 20cef11f0..4089385ee 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 4ff189181..3368395d9 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"), }