diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 45569e9b05..c74b0f9e6f 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -10,7 +10,7 @@ from django.conf import settings from .module_render import get_module from xmodule.course_module import CourseDescriptor from xmodule.modulestore import Location, XML_MODULESTORE_TYPE -from xmodule.modulestore.django import modulestore +from xmodule.modulestore.django import modulestore, loc_mapper from xmodule.contentstore.content import StaticContent from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError from courseware.model_data import FieldDataCache @@ -315,17 +315,12 @@ def sort_by_announcement(courses): return courses -def get_cms_course_link_by_id(course_id): +def get_cms_course_link(course): """ - Returns a proto-relative link to course_index for editing the course in cms, assuming that the course is actually - cms-backed. If course_id is improperly formatted, just return the root of the cms + Returns a link to course_index for editing the course in cms, + assuming that the course is actually cms-backed. """ - format_str = r'^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$' - host = "//{}/".format(settings.CMS_BASE) # protocol-relative - m_obj = re.match(format_str, course_id) - if m_obj: - return "{host}{org}/{course}/course/{name}".format(host=host, - org=m_obj.group('org'), - course=m_obj.group('course'), - name=m_obj.group('name')) - return host + locator = loc_mapper().translate_location( + course.location.course_id, course.location, False, True + ) + return "//" + settings.CMS_BASE + locator.url_reverse('course/', '') diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py index 7760791933..8dcab808a3 100644 --- a/lms/djangoapps/courseware/tests/test_courses.py +++ b/lms/djangoapps/courseware/tests/test_courses.py @@ -4,16 +4,19 @@ Tests for course access """ import mock -from django.test import TestCase +from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from django.http import Http404 from django.test.utils import override_settings -from courseware.courses import get_course_by_id, get_course, get_cms_course_link_by_id +from courseware.courses import get_course_by_id, get_course, get_cms_course_link from xmodule.modulestore.django import get_default_store_name_for_current_request +from xmodule.modulestore.tests.factories import CourseFactory +from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE + CMS_BASE_TEST = 'testcms' -class CoursesTest(TestCase): +class CoursesTest(ModuleStoreTestCase): """Test methods related to fetching courses.""" def test_get_course_by_id_invalid_chars(self): @@ -38,21 +41,41 @@ class CoursesTest(TestCase): get_course('MITx/foobar/business and management') get_course('MITx/foobar/NiñøJoséMaríáßç') - @override_settings(CMS_BASE=CMS_BASE_TEST) - def test_get_cms_course_link_by_id(self): + @override_settings( + MODULESTORE=TEST_DATA_MONGO_MODULESTORE, CMS_BASE=CMS_BASE_TEST + ) + def test_get_cms_course_link(self): """ Tests that get_cms_course_link_by_id returns the right thing """ - self.assertEqual("//{}/".format(CMS_BASE_TEST), get_cms_course_link_by_id("blah_bad_course_id")) - self.assertEqual("//{}/".format(CMS_BASE_TEST), get_cms_course_link_by_id("too/too/many/slashes")) - self.assertEqual("//{}/org/num/course/name".format(CMS_BASE_TEST), get_cms_course_link_by_id('org/num/name')) - @mock.patch('xmodule.modulestore.django.get_current_request_hostname', mock.Mock(return_value='preview.localhost')) - @override_settings(HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': 'draft'}) + self.course = CourseFactory.create( + org='org', number='num', display_name='name' + ) + + self.assertEqual( + u"//{}/course/org.num.name/branch/draft/block/name".format( + CMS_BASE_TEST + ), + get_cms_course_link(self.course) + ) + + @mock.patch( + 'xmodule.modulestore.django.get_current_request_hostname', + mock.Mock(return_value='preview.localhost') + ) + @override_settings( + HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': 'draft'} + ) def test_default_modulestore_preview_mapping(self): self.assertEqual(get_default_store_name_for_current_request(), 'draft') - @mock.patch('xmodule.modulestore.django.get_current_request_hostname', mock.Mock(return_value='localhost')) - @override_settings(HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': 'draft'}) + @mock.patch( + 'xmodule.modulestore.django.get_current_request_hostname', + mock.Mock(return_value='localhost') + ) + @override_settings( + HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': 'draft'} + ) def test_default_modulestore_published_mapping(self): self.assertEqual(get_default_store_name_for_current_request(), 'default') diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py index c7aa4a7c1e..fdeb023a58 100644 --- a/lms/djangoapps/instructor/views/instructor_dashboard.py +++ b/lms/djangoapps/instructor/views/instructor_dashboard.py @@ -19,7 +19,7 @@ from xmodule.modulestore.django import modulestore from xblock.field_data import DictFieldData from xblock.fields import ScopeIds from courseware.access import has_access -from courseware.courses import get_course_by_id, get_cms_course_link_by_id +from courseware.courses import get_course_by_id, get_cms_course_link from django_comment_client.utils import has_forum_access from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR from student.models import CourseEnrollment @@ -61,7 +61,7 @@ def instructor_dashboard_2(request, course_id): studio_url = None if is_studio_course: - studio_url = get_cms_course_link_by_id(course_id) + studio_url = get_cms_course_link(course) enrollment_count = sections[0]['enrollment_count'] disable_buttons = False diff --git a/lms/djangoapps/instructor/views/legacy.py b/lms/djangoapps/instructor/views/legacy.py index 78bd9ce9d0..5efd340578 100644 --- a/lms/djangoapps/instructor/views/legacy.py +++ b/lms/djangoapps/instructor/views/legacy.py @@ -34,7 +34,7 @@ from bulk_email.models import CourseEmail, CourseAuthorization from courseware import grades from courseware.access import (has_access, get_access_group_name, course_beta_test_group_name) -from courseware.courses import get_course_with_access, get_cms_course_link_by_id +from courseware.courses import get_course_with_access, get_cms_course_link from courseware.models import StudentModule from django_comment_common.models import (Role, FORUM_ROLE_ADMINISTRATOR, @@ -827,7 +827,7 @@ def instructor_dashboard(request, course_id): studio_url = None if is_studio_course: - studio_url = get_cms_course_link_by_id(course_id) + studio_url = get_cms_course_link(course) email_editor = None # HTML editor for email diff --git a/lms/envs/test.py b/lms/envs/test.py index 117ccb7f1f..49f8d29aa2 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -121,6 +121,12 @@ CONTENTSTORE = { } } +DOC_STORE_CONFIG = { + 'host': 'localhost', + 'db': 'test_xmodule', + 'collection': 'test_modulestore', +} + DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3',