From 75ba73cd7605737176c60b12a4ff7b418547d320 Mon Sep 17 00:00:00 2001 From: Patrick Gan Date: Wed, 16 Oct 2024 10:33:20 +0800 Subject: [PATCH 1/3] Make sure degree level is also considered when searching in the programme finder --- rca/programmes/models.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rca/programmes/models.py b/rca/programmes/models.py index 898f68fed..ddd8c2e61 100644 --- a/rca/programmes/models.py +++ b/rca/programmes/models.py @@ -870,6 +870,8 @@ class ProgrammePage(TapMixin, ContactFieldsMixin, BasePage): ) ], ), + # Combination of title + degree level. + index.AutocompleteField("full_title", boost=2), ] api_fields = [ # Fields for filtering and display, shared with shortcourses.ShortCoursePage. @@ -896,6 +898,10 @@ def __str__(self): if self.degree_level: bits.append(str(self.degree_level)) return " ".join(bits) + + @property + def full_title(self): + return f"{self.title} {self.degree_level.title}" @property def introduction(self): From 1a074a3f2ff93e1cd2ae32f2e78181cbae3dc5b4 Mon Sep 17 00:00:00 2001 From: Patrick Gan Date: Wed, 16 Oct 2024 13:50:08 +0800 Subject: [PATCH 2/3] Add a special distinct filter so results arent duplicated --- rca/wagtailapi/filters.py | 5 +++++ rca/wagtailapi/views.py | 1 + 2 files changed, 6 insertions(+) diff --git a/rca/wagtailapi/filters.py b/rca/wagtailapi/filters.py index 2ecc7f68c..2ab8ecf11 100644 --- a/rca/wagtailapi/filters.py +++ b/rca/wagtailapi/filters.py @@ -162,3 +162,8 @@ def filter_queryset(self, request, queryset, view): ) return queryset + + +class DistinctFilter(filters.BaseFilterBackend): + def filter_queryset(self, request, queryset, view): + return queryset.distinct() \ No newline at end of file diff --git a/rca/wagtailapi/views.py b/rca/wagtailapi/views.py index b34b63028..9b4c305af 100644 --- a/rca/wagtailapi/views.py +++ b/rca/wagtailapi/views.py @@ -21,6 +21,7 @@ class PagesAPIViewSet(views.PagesAPIViewSet): filters.RelatedSchoolsFilter, filters.SubjectsFilter, filters.StudyModeFilter, + filters.DistinctFilter, filters.SearchFilter, ] From 7c1513feb3cc550641a9a7aa4acfdb986a849d24 Mon Sep 17 00:00:00 2001 From: Patrick Gan Date: Wed, 16 Oct 2024 15:16:17 +0800 Subject: [PATCH 3/3] Fix duplication issue and fix tests as well --- rca/programmes/models.py | 2 +- rca/programmes/tests/test_api.py | 105 +++++++++++++++++++++++++++++++ rca/wagtailapi/filters.py | 2 +- 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 rca/programmes/tests/test_api.py diff --git a/rca/programmes/models.py b/rca/programmes/models.py index ddd8c2e61..690dd4593 100644 --- a/rca/programmes/models.py +++ b/rca/programmes/models.py @@ -898,7 +898,7 @@ def __str__(self): if self.degree_level: bits.append(str(self.degree_level)) return " ".join(bits) - + @property def full_title(self): return f"{self.title} {self.degree_level.title}" diff --git a/rca/programmes/tests/test_api.py b/rca/programmes/tests/test_api.py new file mode 100644 index 000000000..76a82105e --- /dev/null +++ b/rca/programmes/tests/test_api.py @@ -0,0 +1,105 @@ +from django.test import TestCase + +from rca.home.models import HomePage +from rca.programmes.factories import DegreeLevelFactory, ProgrammePageFactory +from rca.programmes.models import ProgrammeStudyMode, ProgrammeStudyModeProgrammePage + + +class ProgrammesAPIResponseTest(TestCase): + def setUp(self): + self.home_page = HomePage.objects.first() + + self.full_time_study_mode = ProgrammeStudyMode.objects.get( + title="Full-time study" + ) + self.part_time_study_mode = ProgrammeStudyMode.objects.get( + title="Part-time study" + ) + + self.programme_page_title = "Print" + self.degree_level_title = "MA" + + degree_level = DegreeLevelFactory(title=self.degree_level_title) + self.programme_page = ProgrammePageFactory( + parent=self.home_page, + title=self.programme_page_title, + degree_level=degree_level, + ) + + self.base_url = ( + "/api/v3/pages/?type=programmes.ProgrammePage" + "&limit=50&fields=summary%2Chero_image_square" + ) + + def test_should_return_if_querying_title_and_degree_level(self): + ProgrammeStudyModeProgrammePage.objects.create( + page=self.programme_page, programme_study_mode=self.full_time_study_mode + ) + + # Check by just using the title of the page. + response = self.client.get( + f"{self.base_url}&full-time=true" + f"&part-time=true&search={self.programme_page_title}" + ) + data = response.json() + + self.assertEqual(data["meta"]["total_count"], 1) + self.assertEqual(data["items"][0]["id"], self.programme_page.id) + + # Check by using the page and degree name. + response = self.client.get( + f"{self.base_url}&full-time=true" + f"&part-time=true&search={self.programme_page_title}+{self.degree_level_title}" + ) + data = response.json() + + self.assertEqual(data["meta"]["total_count"], 1) + self.assertEqual(data["items"][0]["id"], self.programme_page.id) + + def test_should_not_return_full_time_programmes_if_full_time_is_false(self): + ProgrammeStudyModeProgrammePage.objects.create( + page=self.programme_page, programme_study_mode=self.full_time_study_mode + ) + + # Set full-time to true first. + response = self.client.get( + f"{self.base_url}&full-time=true" + f"&part-time=true&search={self.programme_page_title}" + ) + data = response.json() + + self.assertEqual(data["meta"]["total_count"], 1) + self.assertEqual(data["items"][0]["id"], self.programme_page.id) + + # Then set it to false - there should be no results now. + response = self.client.get( + f"{self.base_url}&full-time=false" + f"&part-time=true&search={self.programme_page_title}" + ) + data = response.json() + + self.assertEqual(data["meta"]["total_count"], 0) + + def test_should_not_return_part_time_programmes_if_part_time_is_false(self): + ProgrammeStudyModeProgrammePage.objects.create( + page=self.programme_page, programme_study_mode=self.part_time_study_mode + ) + + # Set part-time to true first. + response = self.client.get( + f"{self.base_url}&full-time=true" + f"&part-time=true&search={self.programme_page_title}" + ) + data = response.json() + + self.assertEqual(data["meta"]["total_count"], 1) + self.assertEqual(data["items"][0]["id"], self.programme_page.id) + + # Then set it to false - there should be no results now. + response = self.client.get( + f"{self.base_url}&full-time=true" + f"&part-time=false&search={self.programme_page_title}+{self.degree_level_title}" + ) + data = response.json() + + self.assertEqual(data["meta"]["total_count"], 0) diff --git a/rca/wagtailapi/filters.py b/rca/wagtailapi/filters.py index 2ab8ecf11..fd23d09b8 100644 --- a/rca/wagtailapi/filters.py +++ b/rca/wagtailapi/filters.py @@ -166,4 +166,4 @@ def filter_queryset(self, request, queryset, view): class DistinctFilter(filters.BaseFilterBackend): def filter_queryset(self, request, queryset, view): - return queryset.distinct() \ No newline at end of file + return queryset.distinct()