diff --git a/core/api.py b/core/api.py index d2e99c2d..21f9818c 100644 --- a/core/api.py +++ b/core/api.py @@ -49,10 +49,14 @@ class UserController(ControllerBase): def fetch_profiles(self, pks: Query[set[int]]): return User.objects.filter(pk__in=pks) - @route.get("/search", response=PaginatedResponseSchema[UserProfileSchema]) + @route.get( + "/search", + response=PaginatedResponseSchema[UserProfileSchema], + url_name="search_users", + ) @paginate(PageNumberPaginationExtra, page_size=20) def search_users(self, filters: Query[UserFilterSchema]): - return filters.filter(User.objects.all()) + return filters.filter(User.objects.order_by("-last_login")) DepthValue = Annotated[int, annotated_types.Ge(0), annotated_types.Le(10)] diff --git a/core/schemas.py b/core/schemas.py index 00551b8a..386a326f 100644 --- a/core/schemas.py +++ b/core/schemas.py @@ -66,7 +66,6 @@ class UserFilterSchema(FilterSchema): SearchQuerySet() .models(User) .autocomplete(auto=slugify(value).replace("-", " ")) - .order_by("-last_update") .values_list("pk", flat=True) ) ) diff --git a/core/tests/test_user.py b/core/tests/test_user.py new file mode 100644 index 00000000..88a318c6 --- /dev/null +++ b/core/tests/test_user.py @@ -0,0 +1,79 @@ +from datetime import timedelta + +from django.core.management import call_command +from django.test import TestCase +from django.urls import reverse +from django.utils.timezone import now +from model_bakery import baker, seq + +from core.baker_recipes import subscriber_user +from core.models import User + + +class TestSearchUsers(TestCase): + @classmethod + def setUpTestData(cls): + User.objects.all().delete() + cls.users = baker.make( + User, + _quantity=11, + first_name=seq("First", suffix="Name"), + last_name=seq("Last", suffix="Name"), + nick_name=seq("Nick", suffix="Name"), + last_login=seq(now() - timedelta(days=30), timedelta(days=1)), + _bulk_create=True, + ) + call_command("update_index", "core", "--remove") + + @classmethod + def tearDownClass(cls): + super().tearDownClass() + # restore the index + call_command("update_index", "core", "--remove") + + def test_order(self): + """Test that users are ordered by last login date.""" + self.client.force_login(subscriber_user.make()) + + response = self.client.get(reverse("api:search_users") + "?search=First") + assert response.status_code == 200 + assert response.json()["count"] == 11 + # The users are ordered by last login date, so we need to reverse the list + assert [r["id"] for r in response.json()["results"]] == [ + u.id for u in self.users[::-1] + ] + + def test_search_case_insensitive(self): + """Test that the search is case insensitive.""" + self.client.force_login(subscriber_user.make()) + + expected = [u.id for u in self.users[::-1]] + for term in ["first", "First", "FIRST"]: + response = self.client.get(reverse("api:search_users") + f"?search={term}") + assert response.status_code == 200 + assert response.json()["count"] == 11 + assert [r["id"] for r in response.json()["results"]] == expected + + def test_search_nick_name(self): + """Test that the search can be done on the nick name.""" + self.client.force_login(subscriber_user.make()) + + # this should return users with nicknames Nick11, Nick10 and Nick1 + response = self.client.get(reverse("api:search_users") + "?search=Nick1") + assert response.status_code == 200 + assert [r["id"] for r in response.json()["results"]] == [ + self.users[10].id, + self.users[9].id, + self.users[0].id, + ] + + def test_search_special_characters(self): + """Test that the search can be done on special characters.""" + belix = baker.make(User, nick_name="Bélix") + call_command("update_index", "core") + self.client.force_login(subscriber_user.make()) + + # this should return users with first names First1 and First10 + response = self.client.get(reverse("api:search_users") + "?search=bél") + assert response.status_code == 200 + assert [r["id"] for r in response.json()["results"]] == [belix.id] diff --git a/core/views/site.py b/core/views/site.py index 82d7f0cf..b016b9af 100644 --- a/core/views/site.py +++ b/core/views/site.py @@ -85,7 +85,7 @@ def search_user(query): SearchQuerySet() .models(User) .autocomplete(auto=query) - .order_by("-last_update")[:20] + .order_by("-last_login")[:20] ) return [r.object for r in res] except TypeError: