From f1b69dd47d7c99b4d913e307d7b8501e06bbd98f Mon Sep 17 00:00:00 2001 From: imperosol Date: Tue, 17 Jun 2025 14:57:46 +0200 Subject: [PATCH 1/2] fix: typo in API name --- api/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/urls.py b/api/urls.py index ed58c790..765fe91e 100644 --- a/api/urls.py +++ b/api/urls.py @@ -2,7 +2,7 @@ from ninja_extra import NinjaExtraAPI api = NinjaExtraAPI( title="PICON", - description="Portail Interaction de Communication avec les Services Étudiants", + description="Portail Interactif de Communication avec les Services Étudiants", version="0.2.0", urls_namespace="api", csrf=True, From 0c442a8f03100e07c47a0327c838c143240d40f5 Mon Sep 17 00:00:00 2001 From: imperosol Date: Tue, 17 Jun 2025 15:31:28 +0200 Subject: [PATCH 2/2] fix: select only active club members on `GET /club/{club_id}` --- club/api.py | 10 +++++--- club/tests/test_club_controller.py | 38 +++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/club/api.py b/club/api.py index ef46e4c7..2e59d3e5 100644 --- a/club/api.py +++ b/club/api.py @@ -1,6 +1,7 @@ from typing import Annotated from annotated_types import MinLen +from django.db.models import Prefetch from ninja.security import SessionAuth from ninja_extra import ControllerBase, api_controller, paginate, route from ninja_extra.pagination import PageNumberPaginationExtra @@ -8,7 +9,7 @@ from ninja_extra.schemas import PaginatedResponseSchema from api.auth import ApiKeyAuth from api.permissions import CanAccessLookup, HasPerm -from club.models import Club +from club.models import Club, Membership from club.schemas import ClubSchema, SimpleClubSchema @@ -33,6 +34,9 @@ class ClubController(ControllerBase): url_name="fetch_club", ) def fetch_club(self, club_id: int): - return self.get_object_or_exception( - Club.objects.prefetch_related("members", "members__user"), id=club_id + prefetch = Prefetch( + "members", queryset=Membership.objects.ongoing().select_related("user") + ) + return self.get_object_or_exception( + Club.objects.prefetch_related(prefetch), id=club_id ) diff --git a/club/tests/test_club_controller.py b/club/tests/test_club_controller.py index ade8eb4d..18a3aef1 100644 --- a/club/tests/test_club_controller.py +++ b/club/tests/test_club_controller.py @@ -1,7 +1,10 @@ +from datetime import date, timedelta + import pytest from django.test import Client from django.urls import reverse from model_bakery import baker +from model_bakery.recipe import Recipe from pytest_django.asserts import assertNumQueries from club.models import Club, Membership @@ -9,13 +12,32 @@ from core.baker_recipes import subscriber_user @pytest.mark.django_db -def test_fetch_club(client: Client): - club = baker.make(Club) - baker.make(Membership, club=club, _quantity=10, _bulk_create=True) - user = subscriber_user.make() - client.force_login(user) - with assertNumQueries(7): - # - 4 queries for authentication - # - 3 queries for the actual data +class TestFetchClub: + @pytest.fixture() + def club(self): + club = baker.make(Club) + last_month = date.today() - timedelta(days=30) + yesterday = date.today() - timedelta(days=1) + membership_recipe = Recipe(Membership, club=club, start_date=last_month) + membership_recipe.make(end_date=None, _quantity=10, _bulk_create=True) + membership_recipe.make(end_date=yesterday, _quantity=10, _bulk_create=True) + return club + + def test_fetch_club_members(self, client: Client, club: Club): + user = subscriber_user.make() + client.force_login(user) res = client.get(reverse("api:fetch_club", kwargs={"club_id": club.id})) assert res.status_code == 200 + member_ids = {member["user"]["id"] for member in res.json()["members"]} + assert member_ids == set( + club.members.ongoing().values_list("user_id", flat=True) + ) + + def test_fetch_club_nb_queries(self, client: Client, club: Club): + user = subscriber_user.make() + client.force_login(user) + with assertNumQueries(6): + # - 4 queries for authentication + # - 2 queries for the actual data + res = client.get(reverse("api:fetch_club", kwargs={"club_id": club.id})) + assert res.status_code == 200