diff --git a/kolibri/core/content/api.py b/kolibri/core/content/api.py index 83724ca071a..b3f13c24c5b 100644 --- a/kolibri/core/content/api.py +++ b/kolibri/core/content/api.py @@ -826,6 +826,8 @@ class OptionalPagination(ValuesViewsetCursorPagination): class OptionalContentNodePagination(OptionalPagination): + use_deprecated_channels_labels = False + def paginate_queryset(self, queryset, request, view=None): # Record the queryset for use in returning available filters self.queryset = queryset @@ -839,7 +841,12 @@ def get_paginated_response(self, data): [ ("more", self.get_more()), ("results", data), - ("labels", get_available_metadata_labels(self.queryset)), + ( + "labels", + get_available_metadata_labels( + self.queryset, self.use_deprecated_channels_labels + ), + ), ] ) ) @@ -864,6 +871,10 @@ def get_paginated_response_schema(self, schema): } +class PublicContentNodePagination(OptionalContentNodePagination): + use_deprecated_channels_labels = True + + @method_decorator(remote_metadata_cache, name="dispatch") class ContentNodeViewset(InternalContentNodeMixin, RemoteMixin, ReadOnlyValuesViewset): pagination_class = OptionalContentNodePagination diff --git a/kolibri/core/content/test/test_content_app.py b/kolibri/core/content/test/test_content_app.py index 09836a5af2e..8c5e6f46ad6 100644 --- a/kolibri/core/content/test/test_content_app.py +++ b/kolibri/core/content/test/test_content_app.py @@ -392,6 +392,23 @@ def test_contentnode_list(self): self.assertEqual(len(response.data), expected_output) self._assert_nodes(response.data, nodes) + def test_contentnode_channel_metadata_label_absent_in_internal_api(self): + response = self._get( + reverse("kolibri:core:contentnode-list"), data={"max_results": 5} + ) + self.assertEqual(response.status_code, 200) + if not self.baseurl: + self.assertNotIn("channels", response.data.get("labels")) + else: + self.assertIn("channels", response.data.get("labels")) + + def test_contentnode_channel_metadata_label_present_in_public_api(self): + response = self._get( + reverse("kolibri:core:publiccontentnode-list"), data={"max_results": 5} + ) + self.assertEqual(response.status_code, 200) + self.assertIn("channels", response.data.get("labels")) + def test_contentnode_etag(self): root = content.ContentNode.objects.get(title="root") nodes = root.get_descendants(include_self=True).filter(available=True) diff --git a/kolibri/core/content/utils/search.py b/kolibri/core/content/utils/search.py index 1658744492d..a7cf56c05d6 100644 --- a/kolibri/core/content/utils/search.py +++ b/kolibri/core/content/utils/search.py @@ -105,14 +105,17 @@ def template(self): ) -def get_available_metadata_labels(base_queryset): # noqa: C901 +def get_available_metadata_labels( # noqa: C901 + base_queryset, use_deprecated_channels_labels=False +): from kolibri.core.device.models import ContentCacheKey content_cache_key = ContentCacheKey.get_cache_key() try: - cache_key = "search-labels:{}:{}".format( + cache_key = "search-labels:{}:{}:{}".format( content_cache_key, hashlib.md5(str(base_queryset.query).encode("utf8")).hexdigest(), + "with-channels" if use_deprecated_channels_labels else "no-channels", ) except EmptyResultSet: return empty_labels @@ -137,7 +140,8 @@ def get_available_metadata_labels(base_queryset): # noqa: C901 if bit_value is not None and bit_value & value["bits"]: output[value["field_name"]].append(value["label"]) output["languages"] = _get_available_languages(base_queryset) - output["channels"] = _get_available_channels(base_queryset) + if use_deprecated_channels_labels: + output["channels"] = _get_available_channels(base_queryset) cache.set(cache_key, output, timeout=None) return cache.get(cache_key) diff --git a/kolibri/core/public/api.py b/kolibri/core/public/api.py index 378878dc590..2ef03163403 100644 --- a/kolibri/core/public/api.py +++ b/kolibri/core/public/api.py @@ -34,7 +34,7 @@ from kolibri.core.content.api import BaseContentNodeMixin from kolibri.core.content.api import BaseContentNodeTreeViewset from kolibri.core.content.api import metadata_cache -from kolibri.core.content.api import OptionalContentNodePagination +from kolibri.core.content.api import PublicContentNodePagination from kolibri.core.content.models import ChannelMetadata from kolibri.core.content.models import ContentNode from kolibri.core.content.models import LocalFile @@ -137,7 +137,7 @@ def get_queryset(self): @method_decorator(public_metadata_cache, name="dispatch") class PublicContentNodeViewSet(BaseContentNodeMixin, ReadOnlyValuesViewset): - pagination_class = OptionalContentNodePagination + pagination_class = PublicContentNodePagination @method_decorator(public_metadata_cache, name="dispatch")