From 279b795152e290bc7d052b4b63ca4cae59ad4866 Mon Sep 17 00:00:00 2001 From: Tore Brede <Tore.Brede@uib.no> Date: Thu, 6 Jan 2022 12:52:25 +0100 Subject: [PATCH] GREG-161: Updating test and formatting --- greg/api/serializers/person.py | 2 +- gregui/api/urls.py | 7 +++- gregui/api/views/person.py | 55 ++++++++++++++++++--------- gregui/tests/api/views/test_search.py | 31 ++++++++++++--- gregui/tests/conftest.py | 10 ++--- 5 files changed, 74 insertions(+), 31 deletions(-) diff --git a/greg/api/serializers/person.py b/greg/api/serializers/person.py index 3d299897..c7d1e085 100644 --- a/greg/api/serializers/person.py +++ b/greg/api/serializers/person.py @@ -4,7 +4,7 @@ from rest_framework.fields import BooleanField, CharField, SerializerMethodField from greg.api.serializers.consent import ConsentSerializerBrief from greg.api.serializers.identity import IdentitySerializer, SpecialIdentitySerializer from greg.api.serializers.role import RoleSerializer, SpecialRoleSerializer -from greg.models import Person, Identity +from greg.models import Person class PersonSerializer(serializers.ModelSerializer): diff --git a/gregui/api/urls.py b/gregui/api/urls.py index 008cc828..5fed05cb 100644 --- a/gregui/api/urls.py +++ b/gregui/api/urls.py @@ -36,7 +36,10 @@ urlpatterns += [ name="invite-resend", ), path("invite/", InvitationView.as_view(), name="invitation"), - path("person/search/", PersonSearchViewSet.as_view({"get": "list"}), name="person-search", - ), + path( + "person/search/", + PersonSearchViewSet.as_view({"get": "list"}), + name="person-search", + ), path("userinfo/", UserInfoView.as_view(), name="userinfo"), ] diff --git a/gregui/api/views/person.py b/gregui/api/views/person.py index cc281a2b..622d9ff7 100644 --- a/gregui/api/views/person.py +++ b/gregui/api/views/person.py @@ -40,7 +40,7 @@ class PersonViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericV class PersonSearchViewSet(GenericViewSet): - """Search for persons using email or phone number""" + """Search for persons using name, email, phone number and birth date""" authentication_classes = [SessionAuthentication, BasicAuthentication] permission_classes = [IsAuthenticated, IsSponsor] @@ -56,12 +56,13 @@ class PersonSearchViewSet(GenericViewSet): ) if len(self.request.query_params["q"]) > 50: - return Response(status=status.HTTP_400_BAD_REQUEST, - data={ - "code": "search_term_too_large", - "message": "Search term is too large", - }, - ) + return Response( + status=status.HTTP_400_BAD_REQUEST, + data={ + "code": "search_term_too_large", + "message": "Search term is too large", + }, + ) hits = self.get_hits() return Response(hits) @@ -70,32 +71,52 @@ class PersonSearchViewSet(GenericViewSet): search = self.request.query_params["q"] split_search = search.split() - words_joined = '|'.join(map(str, split_search)) - search_regex = r'^(%s)' % words_joined + words_joined = "|".join(map(str, split_search)) + # Create a regex with the terms in the search or-ed together. This will trigger a match + # if one of the fields that are being searched contains one of the terms + search_regex = r"^(%s)" % words_joined hits = [] - persons = Person.objects.filter(Q(first_name__iregex=search_regex) | - Q(last_name__iregex=search_regex) | - Q(date_of_birth__iregex=search_regex))[:10] + # First look for hits on name and birth date + persons = Person.objects.filter( + Q(first_name__iregex=search_regex) + | Q(last_name__iregex=search_regex) + | Q(date_of_birth__iregex=search_regex) + )[:10] included_persons = [] for person in persons: - hits.append({"pid": person.id, "first": person.first_name, "last": person.last_name}) + hits.append( + {"pid": person.id, "first": person.first_name, "last": person.last_name} + ) included_persons.append(person.id) + if len(hits) == 10: + # Max number of hits, no need to search more + return hits + + # Look for hits in e-mail and mobile phone identities = Identity.objects.filter( value__iregex=search_regex, type__in=[ Identity.IdentityType.PRIVATE_EMAIL, Identity.IdentityType.PRIVATE_MOBILE_NUMBER, ], - )[:10] + )[: (10 - len(hits))] for identity in identities: if identity.person_id in included_persons: continue - hits.append({"pid": identity.person_id, "first": identity.person.first_name, "last": identity.person.last_name, "value": identity.value, "type": identity.type}) + hits.append( + { + "pid": identity.person_id, + "first": identity.person.first_name, + "last": identity.person.last_name, + "value": identity.value, + "type": identity.type, + } + ) return hits @@ -126,6 +147,6 @@ class GuestInfoViewSet(mixins.ListModelMixin, GenericViewSet): units = user.sponsor.get_allowed_units() return ( Person.objects.filter(roles__orgunit__in=list(units)) - .distinct() - .order_by("id") + .distinct() + .order_by("id") ) diff --git a/gregui/tests/api/views/test_search.py b/gregui/tests/api/views/test_search.py index 29157589..03422aec 100644 --- a/gregui/tests/api/views/test_search.py +++ b/gregui/tests/api/views/test_search.py @@ -4,8 +4,8 @@ from rest_framework.reverse import reverse @pytest.mark.django_db -def test_name_search(client, log_in, user_sponsor, create_person): - person = create_person( +def test_no_search_parameter_fails(client, log_in, user_sponsor, create_person): + create_person( first_name="foo", last_name="bar", email="foo@bar.com", @@ -26,7 +26,7 @@ def test_date_of_birth_search(client, log_in, user_sponsor, create_person): first_name="foo", last_name="bar", email="foo@bar.com", - date_of_birth="2005-06-20" + date_of_birth="2005-06-20", ) url = reverse("gregui-v1:person-search") + "?q=2005-06-20" @@ -47,18 +47,37 @@ def test_multiple_words_search(client, log_in, user_sponsor, create_person): person = create_person( first_name="foo", last_name="bar", + email="example@company.com", + ) + person2 = create_person( + first_name="test", + last_name="test2", email="foo@bar.com", - date_of_birth="2005-06-20" + date_of_birth="2006-06-20", + ) + person3 = create_person( + first_name="Bob", + last_name="Smith", + email="bob@smith.com", + date_of_birth="2005-06-20", + ) + person4 = create_person( + first_name="Frank", + last_name="Paulsen", + email="frank@paulsen.com", ) - url = reverse("gregui-v1:person-search") + "?q=foo%20bar" + url = reverse("gregui-v1:person-search") + "?q=foo%20bar%202005-06-20" log_in(user_sponsor) response = client.get(url) - assert len(response.data) == 1 + assert len(response.data) == 3 person_ids = list(map(lambda x: x["pid"], response.data)) assert person.id in person_ids + assert person2.id in person_ids + assert person3.id in person_ids + assert person4.id not in person_ids assert response.status_code == status.HTTP_200_OK diff --git a/gregui/tests/conftest.py b/gregui/tests/conftest.py index 694e6769..565bebee 100644 --- a/gregui/tests/conftest.py +++ b/gregui/tests/conftest.py @@ -326,7 +326,9 @@ def invitation_link_expired( @pytest.fixture -def create_person() -> Callable[[str, str, str, Optional[str], Optional[str], Optional[datetime.date]], Person]: +def create_person() -> Callable[ + [str, str, str, Optional[str], Optional[str], Optional[datetime.date]], Person +]: # TODO fix the typing... def create_person( first_name: str, @@ -334,12 +336,10 @@ def create_person() -> Callable[[str, str, str, Optional[str], Optional[str], Op email: str = None, nin: str = None, feide_id: str = None, - date_of_birth: datetime.date = None + date_of_birth: datetime.date = None, ) -> Person: person = Person.objects.create( - first_name=first_name, - last_name=last_name, - date_of_birth=date_of_birth + first_name=first_name, last_name=last_name, date_of_birth=date_of_birth ) if nin: -- GitLab