diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 2595375..be4dd4c 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -206,6 +206,10 @@ class UserViewSet( ) ) + # Exclude all users already in the given team + if team_id := self.request.GET.get("team_id", ""): + queryset = queryset.exclude(teams__id=team_id) + # Search by case-insensitive and accent-insensitive trigram similarity if query := self.request.GET.get("q", ""): similarity = Max( diff --git a/src/backend/core/tests/test_api_users.py b/src/backend/core/tests/test_api_users.py index c478232..9623649 100644 --- a/src/backend/core/tests/test_api_users.py +++ b/src/backend/core/tests/test_api_users.py @@ -218,6 +218,64 @@ def test_api_users_authenticated_list_by_name_and_email(): assert user_ids == [str(nicole.user.id), str(frank.user.id), str(david.user.id)] +def test_api_users_authenticated_list_exclude_users_already_in_team( + django_assert_num_queries, +): + """ + Authenticated users should be able to search users + but the result should exclude all users already in the given team. + """ + user = factories.UserFactory(email="tester@ministry.fr") + factories.IdentityFactory(user=user, email=user.email, name="john doe") + client = APIClient() + client.force_login(user) + + dave = factories.IdentityFactory(name="dave bowman", email=None, is_main=True) + nicole = factories.IdentityFactory(name="nicole foole", email=None, is_main=True) + frank = factories.IdentityFactory(name="frank poole", email=None, is_main=True) + mary = factories.IdentityFactory(name="mary poole", email=None, is_main=True) + factories.IdentityFactory(name="heywood floyd", email=None, is_main=True) + factories.IdentityFactory(name="Andrei Smyslov", email=None, is_main=True) + factories.TeamFactory.create_batch(10) + + # Add Dave and Frank in the same team + team = factories.TeamFactory( + users=[ + (dave.user, models.RoleChoices.MEMBER), + (frank.user, models.RoleChoices.MEMBER), + ] + ) + factories.TeamFactory(users=[(nicole.user, models.RoleChoices.MEMBER)]) + + # Search user to add him/her to a team, we give a team id to the request + # to exclude all users already in the team + + # We can't find David Bowman because he is already a member of the given team + # 2 queries are needed here: + # - user authenticated + # - search user query + with django_assert_num_queries(2): + response = client.get( + f"/api/v1.0/users/?q=bowman&team_id={team.id}", + ) + assert response.status_code == HTTP_200_OK + assert response.json()["results"] == [] + + # We can only find Nicole and Mary because Frank is already a member of the given team + # 4 queries are needed here: + # - user authenticated + # - search user query + # - User + # - Identity + with django_assert_num_queries(4): + response = client.get( + f"/api/v1.0/users/?q=ool&team_id={team.id}", + ) + assert response.status_code == HTTP_200_OK + user_ids = sorted([user["id"] for user in response.json()["results"]]) + assert user_ids == sorted([str(mary.user.id), str(nicole.user.id)]) + + def test_api_users_authenticated_list_multiple_identities_single_user(): """ User with multiple identities should appear only once in results.