From dcdc4af3e0409ae808c85c2aade2a9dbe11f3677 Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Tue, 21 Feb 2023 12:21:29 -0400 Subject: [PATCH] feat: Use case-insensitive matching for document searches (#5166) * fix: Use case insensitive match for group acronym in doc search * fix: Use case insensitive match for doc.search_by_name view * fix: Use case insensitive match for doc names in ipr.search view * test: Test case insensitivity in doc search/search_for_name --- ietf/doc/tests.py | 31 +++++++++++++++++++++++++++++++ ietf/doc/views_search.py | 8 ++++---- ietf/ipr/tests.py | 8 ++++++++ ietf/ipr/views.py | 4 ++-- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 7067a942e..a65be156c 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -93,6 +93,10 @@ class SearchTests(TestCase): self.assertEqual(r.status_code, 200) self.assertContains(r, "draft-foo-mars-test") + r = self.client.get(base_url + "?olddrafts=on&name=FoO") # mixed case + self.assertEqual(r.status_code, 200) + self.assertContains(r, "draft-foo-mars-test") + # find by rfc/active/inactive draft.set_state(State.objects.get(type="draft", slug="rfc")) r = self.client.get(base_url + "?rfcs=on&name=%s" % draft.name) @@ -126,6 +130,10 @@ class SearchTests(TestCase): self.assertEqual(r.status_code, 200) self.assertContains(r, draft.title) + r = self.client.get(base_url + "?activedrafts=on&by=group&group=%s" % draft.group.acronym.swapcase()) + self.assertEqual(r.status_code, 200) + self.assertContains(r, draft.title) + # find by area r = self.client.get(base_url + "?activedrafts=on&by=area&area=%s" % draft.group.parent_id) self.assertEqual(r.status_code, 200) @@ -167,16 +175,39 @@ class SearchTests(TestCase): self.assertEqual(r.status_code, 302) self.assertEqual(urlparse(r["Location"]).path, urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name))) + # mixed-up case exact match + r = self.client.get(urlreverse('ietf.doc.views_search.search_for_name', kwargs=dict(name=draft.name.swapcase()))) + self.assertEqual(r.status_code, 302) + self.assertEqual(urlparse(r["Location"]).path, urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name))) + # prefix match r = self.client.get(urlreverse('ietf.doc.views_search.search_for_name', kwargs=dict(name="-".join(draft.name.split("-")[:-1])))) self.assertEqual(r.status_code, 302) self.assertEqual(urlparse(r["Location"]).path, urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name))) + # mixed-up case prefix match + r = self.client.get( + urlreverse( + 'ietf.doc.views_search.search_for_name', + kwargs=dict(name="-".join(draft.name.swapcase().split("-")[:-1])), + )) + self.assertEqual(r.status_code, 302) + self.assertEqual(urlparse(r["Location"]).path, urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name))) + # non-prefix match r = self.client.get(urlreverse('ietf.doc.views_search.search_for_name', kwargs=dict(name="-".join(draft.name.split("-")[1:])))) self.assertEqual(r.status_code, 302) self.assertEqual(urlparse(r["Location"]).path, urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name))) + # mixed-up case non-prefix match + r = self.client.get( + urlreverse( + 'ietf.doc.views_search.search_for_name', + kwargs=dict(name="-".join(draft.name.swapcase().split("-")[1:])), + )) + self.assertEqual(r.status_code, 302) + self.assertEqual(urlparse(r["Location"]).path, urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name))) + # other doctypes than drafts doc = Document.objects.get(name='charter-ietf-mars') r = self.client.get(urlreverse('ietf.doc.views_search.search_for_name', kwargs=dict(name='charter-ietf-ma'))) diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py index de1f40260..92dcfe4aa 100644 --- a/ietf/doc/views_search.py +++ b/ietf/doc/views_search.py @@ -188,7 +188,7 @@ def retrieve_search_results(form, all_types=False): Q(documentauthor__person__email__address__icontains=query["author"]) ) elif by == "group": - docs = docs.filter(group__acronym=query["group"]) + docs = docs.filter(group__acronym__iexact=query["group"]) elif by == "area": docs = docs.filter(Q(group__type="wg", group__parent=query["area"]) | Q(group=query["area"])).distinct() @@ -245,15 +245,15 @@ def frontpage(request): def search_for_name(request, name): def find_unique(n): - exact = DocAlias.objects.filter(name=n).first() + exact = DocAlias.objects.filter(name__iexact=n).first() if exact: return exact.name - aliases = DocAlias.objects.filter(name__startswith=n)[:2] + aliases = DocAlias.objects.filter(name__istartswith=n)[:2] if len(aliases) == 1: return aliases[0].name - aliases = DocAlias.objects.filter(name__contains=n)[:2] + aliases = DocAlias.objects.filter(name__icontains=n)[:2] if len(aliases) == 1: return aliases[0].name diff --git a/ietf/ipr/tests.py b/ietf/ipr/tests.py index 9caeb2f29..3afb47bbf 100644 --- a/ietf/ipr/tests.py +++ b/ietf/ipr/tests.py @@ -147,10 +147,18 @@ class IprTests(TestCase): r = self.client.get(url + "?submit=draft&id=%s" % draft.name) self.assertContains(r, ipr.title) + # find by id, mixed case letters + r = self.client.get(url + "?submit=draft&id=%s" % draft.name.swapcase()) + self.assertContains(r, ipr.title) + # find draft r = self.client.get(url + "?submit=draft&draft=%s" % draft.name) self.assertContains(r, ipr.title) + # find draft, mixed case letters + r = self.client.get(url + "?submit=draft&draft=%s" % draft.name.swapcase()) + self.assertContains(r, ipr.title) + # search + select document r = self.client.get(url + "?submit=draft&draft=draft") self.assertContains(r, draft.name) diff --git a/ietf/ipr/views.py b/ietf/ipr/views.py index 2450e5313..ed4e5b35b 100644 --- a/ietf/ipr/views.py +++ b/ietf/ipr/views.py @@ -663,11 +663,11 @@ def search(request): doc = q if docid: - start = DocAlias.objects.filter(name=docid) + start = DocAlias.objects.filter(name__iexact=docid) else: if search_type == "draft": q = normalize_draftname(q) - start = DocAlias.objects.filter(name__contains=q, name__startswith="draft") + start = DocAlias.objects.filter(name__icontains=q, name__startswith="draft") elif search_type == "rfc": start = DocAlias.objects.filter(name="rfc%s" % q.lstrip("0"))