From 75a26b62b5985b27ba849b0a0f54d073b3f494ad Mon Sep 17 00:00:00 2001 From: Sanford Student Date: Fri, 19 Feb 2016 10:04:59 -0500 Subject: [PATCH] MA-1919 making mobile handout links accommodate jump to id's and course links --- .../mobile_api/course_info/tests.py | 132 +++++++++++------- .../mobile_api/course_info/views.py | 41 ++++-- 2 files changed, 112 insertions(+), 61 deletions(-) diff --git a/lms/djangoapps/mobile_api/course_info/tests.py b/lms/djangoapps/mobile_api/course_info/tests.py index 7150624f9335..87120064b8ce 100644 --- a/lms/djangoapps/mobile_api/course_info/tests.py +++ b/lms/djangoapps/mobile_api/course_info/tests.py @@ -84,60 +84,98 @@ def test_updates(self, new_format): self.assertIn("Update" + str(num), update_data['content']) +@ddt.ddt class TestHandouts(MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTestMixin, MilestonesTestCaseMixin): """ Tests for /api/mobile/v0.5/course_info/{course_id}/handouts """ REVERSE_INFO = {'name': 'course-handouts-list', 'params': ['course_id']} - def setUp(self): - super(TestHandouts, self).setUp() - - # Deleting handouts fails with split modulestore because the handout has no parent. - # This needs further investigation to determine if it is a bug in the split modulestore. - # pylint: disable=protected-access - self.store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo) - - # use toy course with handouts, and make it mobile_available - course_items = import_course_from_xml(self.store, self.user.id, settings.COMMON_TEST_DATA_ROOT, ['toy']) + @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) + def test_handouts(self, default_ms): + with self.store.default_store(default_ms): + self.add_mobile_available_toy_course() + response = self.api_response(expected_response_code=200) + self.assertIn("Sample", response.data['handouts_html']) + + @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) + def test_no_handouts(self, default_ms): + with self.store.default_store(default_ms): + self.add_mobile_available_toy_course() + + # delete handouts in course + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id): + self.store.delete_item(handouts_usage_key, self.user.id) + + response = self.api_response(expected_response_code=200) + self.assertIsNone(response.data['handouts_html']) + + @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) + def test_empty_handouts(self, default_ms): + with self.store.default_store(default_ms): + self.add_mobile_available_toy_course() + + # set handouts to empty tags + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + underlying_handouts.data = "
    " + self.store.update_item(underlying_handouts, self.user.id) + response = self.api_response(expected_response_code=200) + self.assertIsNone(response.data['handouts_html']) + + @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) + def test_handouts_static_rewrites(self, default_ms): + with self.store.default_store(default_ms): + self.add_mobile_available_toy_course() + + # check that we start with relative static assets + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + self.assertIn('\'/static/', underlying_handouts.data) + + # but shouldn't finish with any + response = self.api_response() + self.assertNotIn('\'/static/', response.data['handouts_html']) + + @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) + def test_jump_to_id_handout_href(self, default_ms): + with self.store.default_store(default_ms): + self.add_mobile_available_toy_course() + + # check that we start with relative static assets + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + underlying_handouts.data = "Intracourse Link" + self.store.update_item(underlying_handouts, self.user.id) + + # but shouldn't finish with any + response = self.api_response() + self.assertIn("/courses/{}/jump_to_id/".format(self.course.id), response.data['handouts_html']) + + @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) + def test_course_url_handout_href(self, default_ms): + with self.store.default_store(default_ms): + self.add_mobile_available_toy_course() + + # check that we start with relative static assets + handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') + underlying_handouts = self.store.get_item(handouts_usage_key) + underlying_handouts.data = "Linked Content" + self.store.update_item(underlying_handouts, self.user.id) + + # but shouldn't finish with any + response = self.api_response() + self.assertIn("/courses/{}/".format(self.course.id), response.data['handouts_html']) + + def add_mobile_available_toy_course(self): + """ use toy course with handouts, and make it mobile_available """ + course_items = import_course_from_xml( + self.store, self.user.id, + settings.COMMON_TEST_DATA_ROOT, ['toy'], + create_if_not_present=True + ) self.course = course_items[0] self.course.mobile_available = True self.store.update_item(self.course, self.user.id) - - def verify_success(self, response): - super(TestHandouts, self).verify_success(response) - self.assertIn('Sample', response.data['handouts_html']) - - def test_no_handouts(self): self.login_and_enroll() - - # delete handouts in course - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id): - self.store.delete_item(handouts_usage_key, self.user.id) - - response = self.api_response(expected_response_code=200) - self.assertIsNone(response.data['handouts_html']) - - def test_empty_handouts(self): - self.login_and_enroll() - - # set handouts to empty tags - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - underlying_handouts = self.store.get_item(handouts_usage_key) - underlying_handouts.data = "
      " - self.store.update_item(underlying_handouts, self.user.id) - response = self.api_response(expected_response_code=200) - self.assertIsNone(response.data['handouts_html']) - - def test_handouts_static_rewrites(self): - self.login_and_enroll() - - # check that we start with relative static assets - handouts_usage_key = self.course.id.make_usage_key('course_info', 'handouts') - underlying_handouts = self.store.get_item(handouts_usage_key) - self.assertIn('\'/static/', underlying_handouts.data) - - # but shouldn't finish with any - response = self.api_response() - self.assertNotIn('\'/static/', response.data['handouts_html']) diff --git a/lms/djangoapps/mobile_api/course_info/views.py b/lms/djangoapps/mobile_api/course_info/views.py index 380ef10af13b..e9e1bd231e79 100644 --- a/lms/djangoapps/mobile_api/course_info/views.py +++ b/lms/djangoapps/mobile_api/course_info/views.py @@ -6,7 +6,7 @@ from rest_framework.response import Response from courseware.courses import get_course_info_section_module -from static_replace import make_static_urls_absolute, replace_static_urls +from static_replace import make_static_urls_absolute from openedx.core.lib.xblock_utils import get_course_update_items from ..utils import mobile_view, mobile_course_access @@ -46,12 +46,7 @@ def list(self, request, course, *args, **kwargs): ] for item in updates_to_show: - content = item['content'] - content = replace_static_urls( - content, - course_id=course.id, - static_asset_path=course.static_asset_path) - item['content'] = make_static_urls_absolute(request, content) + item['content'] = apply_wrappers_to_content(item['content'], course_updates_module, request) return Response(updates_to_show) @@ -82,14 +77,32 @@ def list(self, request, course, *args, **kwargs): if course_handouts_module.data == "
        ": handouts_html = None else: - handouts_html = course_handouts_module.data - handouts_html = replace_static_urls( - handouts_html, - course_id=course.id, - static_asset_path=course.static_asset_path - ) - handouts_html = make_static_urls_absolute(self.request, handouts_html) + handouts_html = apply_wrappers_to_content(course_handouts_module.data, course_handouts_module, request) return Response({'handouts_html': handouts_html}) else: # course_handouts_module could be None if there are no handouts return Response({'handouts_html': None}) + + +def apply_wrappers_to_content(content, module, request): + """ + Updates a piece of html content with the filter functions stored in its module system, then replaces any + static urls with absolute urls. + + Args: + content: The html content to which to apply the content wrappers generated for this module system. + module: The module containing a reference to the module system which contains functions to apply to the + content. These functions include: + * Replacing static url's + * Replacing course url's + * Replacing jump to id url's + request: The request, used to replace static URLs with absolute URLs. + + Returns: A piece of html content containing the original content updated by each wrapper. + + """ + content = module.system.replace_urls(content) + content = module.system.replace_course_urls(content) + content = module.system.replace_jump_to_id_urls(content) + + return make_static_urls_absolute(request, content)