diff --git a/learning_assistant/api.py b/learning_assistant/api.py index 17bb9f4..03bf5f0 100644 --- a/learning_assistant/api.py +++ b/learning_assistant/api.py @@ -1,7 +1,10 @@ """ Library for the learning_assistant app. """ -from learning_assistant.constants import ACCEPTED_CATEGORY_TYPES, CATEGORY_TYPE_MAP +from django.conf import settings +from django.core.cache import cache + +from learning_assistant.constants import ACCEPTED_CATEGORY_TYPES, CATEGORY_TYPE_MAP, UNIT_CONTENT_CACHE_KEY_TPL from learning_assistant.models import CoursePrompt from learning_assistant.platform_imports import ( block_get_children, @@ -93,8 +96,17 @@ def get_block_content(request, user_id, course_id, unit_usage_key): length - the cummulative length of a block's children's content items - a list of dictionaries containing the content type and text for each child """ - block = get_single_block(request, user_id, course_id, unit_usage_key) - - length, items = _get_children_contents(block) - - return length, items + cache_key = UNIT_CONTENT_CACHE_KEY_TPL.format( + user_id=user_id, + course_id=course_id, + unit_usage_key=unit_usage_key + ) + cache_data = cache.get(cache_key) + + if not isinstance(cache_data, dict): + block = get_single_block(request, user_id, course_id, unit_usage_key) + length, items = _get_children_contents(block) + cache_data = {'content_length': length, 'content_items': items} + cache.set(cache_key, cache_data, getattr(settings, 'LEARNING_ASSISTANT_CACHE_TIMEOUT', 360)) + + return cache_data['content_length'], cache_data['content_items'] diff --git a/learning_assistant/constants.py b/learning_assistant/constants.py index 06097ff..6d34d34 100644 --- a/learning_assistant/constants.py +++ b/learning_assistant/constants.py @@ -14,3 +14,5 @@ "html": "TEXT", "video": "VIDEO", } + +UNIT_CONTENT_CACHE_KEY_TPL = 'learning_assistant:{user_id}:{course_id}:{unit_usage_key}' diff --git a/learning_assistant/text_utils.py b/learning_assistant/text_utils.py index 728fd14..b97872c 100644 --- a/learning_assistant/text_utils.py +++ b/learning_assistant/text_utils.py @@ -34,7 +34,7 @@ def __init__(self): def handle_starttag(self, tag, _): """On each tag, check whether this is a tag we think is content.""" - tags_to_filter = getattr(settings, 'HTML_TAGS_TO_REMOVE', None) + tags_to_filter = getattr(settings, 'LEARNING_ASSISTANT_HTML_TAGS_TO_REMOVE', None) self._is_content = not (tags_to_filter and tag in tags_to_filter) def handle_data(self, data): diff --git a/test_settings.py b/test_settings.py index ea6e856..282b3db 100644 --- a/test_settings.py +++ b/test_settings.py @@ -69,3 +69,9 @@ def root(*args): DISCOVERY_BACKEND_SERVICE_EDX_OAUTH2_PROVIDER_URL = 'http://edx.devstack.lms:18000/oauth2' DISCOVERY_BACKEND_SERVICE_EDX_OAUTH2_KEY = 'discovery-backend-service-key' DISCOVERY_BACKEND_SERVICE_EDX_OAUTH2_SECRET = 'discovery-backend-service-secret' + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + } +} diff --git a/tests/test_api.py b/tests/test_api.py index bf198d7..ad145e8 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -4,6 +4,7 @@ from unittest.mock import MagicMock, patch import ddt +from django.core.cache import cache from django.test import TestCase from opaque_keys.edx.keys import UsageKey @@ -91,6 +92,8 @@ class GetBlockContentAPITests(TestCase): """ def setUp(self): + cache.clear() + self.children = [ FakeChild('html', '01', '''

@@ -187,7 +190,17 @@ def test_get_block_content(self, mock_get_children_contents, mock_get_single_blo length, items = get_block_content(request, user_id, course_id, unit_usage_key) + mock_get_children_contents.assert_called_once() mock_get_children_contents.assert_called_with(self.block) self.assertEqual(length, len(block_content)) self.assertEqual(items, content_items) + + # call get_block_content again with same args to assert that cache is used + length, items = get_block_content(request, user_id, course_id, unit_usage_key) + + # assert that the mock for _get_children_contents has not been called again, + # as subsequent calls should hit the cache + mock_get_children_contents.assert_called_once() + self.assertEqual(length, len(block_content)) + self.assertEqual(items, content_items)