Repository: openfun/richie

Issue:
🐛(search) do not include unlisted courses in the search engine facets' counters
## Bug Report

**Problematic Behavior**
The search engine filters still display unlisted courses in the facets counter. Furthermore, this introduces a discrepancy between the count displayed in the catalog and that in the facets (see at 1'15 in the video below).

**Expected behavior/code**
Using the flag `is_listed: False` (introduced with this PR https://github.com/openfun/richie/pull/1177) should remove the course from the facet's counter. 

**Steps to Reproduce**
1. Log in as an admin on demo.richie.education
2. Go to https://demo.richie.education/fr/cours/?limit=21&offset=0&subjects=120
3. Click on one of the 3 courses displayed in the Health category (for instance)
4. On the course page, click on Page > Course settings, uncheck the `Is_listed` option, then Save
6. Publish the page and return to the catalog
7. The Health facet displays 2 courses with a counter of 3

**Environment**
Richie version: 2.24.1

**Additional context/Screenshots**

[Capture vidéo du 2023-10-27 17-37-23.webm](https://github.com/openfun/richie/assets/23249365/d32fb500-10c6-400b-b49d-d8e34518cb29)



Discussion:

Resolving patch:
diff --git a/src/richie/apps/search/forms.py b/src/richie/apps/search/forms.py
--- a/src/richie/apps/search/forms.py
+++ b/src/richie/apps/search/forms.py
@@ -167,7 +167,8 @@ def get_queries(self):
                     ...
                 ]
         """
-        queries = []
+        # Always filter out courses that are not flagged for listing
+        queries = [{"key": "is_listed", "fragment": [{"term": {"is_listed": True}}]}]
 
         # Add the query fragments of each filter definition to the list of queries
         for filter_definition in FILTERS.values():
@@ -258,8 +259,6 @@ def build_es_query(self):
             "function_score": {
                 "query": {
                     "bool": {
-                        # Always filter out courses that are not flagged for listing
-                        "filter": {"term": {"is_listed": True}},
                         "must":
                         # queries => map(pluck("fragment")) => flatten()
                         [


Test patch:
diff --git a/tests/apps/search/test_forms_search_courses.py b/tests/apps/search/test_forms_search_courses.py
--- a/tests/apps/search/test_forms_search_courses.py
+++ b/tests/apps/search/test_forms_search_courses.py
@@ -249,18 +249,24 @@ def test_forms_courses_multi_values_in_querystring(self, *_):
 
     def test_forms_courses_build_es_query_search_by_match_text(self, *_):
         """
-        Happy path: build a query that filters courses by matching text
+        Happy path: build a query that filters courses by matching text. A filter to
+        include only listed courses should be added to both query and aggregations.
         """
         form = CourseSearchForm(
             data=QueryDict(query_string="limit=2&offset=20&query=some%20phrase%20terms")
         )
         self.assertTrue(form.is_valid())
+        es_query = form.build_es_query()
+        query = es_query[2]
+        aggs = es_query[3]
+
+        # Query should include only listed courses
         self.assertEqual(
-            form.build_es_query()[2]["function_score"]["query"],
+            query["function_score"]["query"],
             {
                 "bool": {
-                    "filter": {"term": {"is_listed": True}},
                     "must": [
+                        {"term": {"is_listed": True}},
                         {
                             "bool": {
                                 "should": [
@@ -299,8 +305,14 @@ def test_forms_courses_build_es_query_search_by_match_text(self, *_):
                                     },
                                 ]
                             }
-                        }
+                        },
                     ],
                 }
             },
         )
+
+        # All aggregations should include only listed courses
+        for agg in list(aggs["all_courses"]["aggregations"].values()):
+            self.assertTrue(
+                {"term": {"is_listed": True}} in agg["filter"]["bool"]["must"]
+            )