diff --git a/openedx/core/constants.py b/openedx/core/constants.py index ad16e9e59529..6d7a51f22edf 100644 --- a/openedx/core/constants.py +++ b/openedx/core/constants.py @@ -6,9 +6,14 @@ # Note: these intentionally greedily grab all chars up to the next slash includingny pluses # DHM: I really wanted to ensure the separators were the same (+ or /) but all patts tried had # too many inadvertent side effects :-( - COURSE_KEY_PATTERN = r'(?P[^/+]+(/|\+)[^/+]+(/|\+)[^/?]+)' COURSE_ID_PATTERN = COURSE_KEY_PATTERN.replace('course_key_string', 'course_id') COURSE_KEY_REGEX = COURSE_KEY_PATTERN.replace('P', ':') + +# This constant can be extended to take into account future urls to negate with the following pattern +# (?=\/(enroll|unenroll|other_patterns)$) +POSTFIXED_PATTERNS_TO_NEGATE = r'(?=\/enroll)$' +CAPTURED_CLEAN_COURSE_ID_PATTERN = r'^(?P.*?)' + COURSE_PUBLISHED = 'published' COURSE_UNPUBLISHED = 'unpublished' diff --git a/openedx/core/lib/request_utils.py b/openedx/core/lib/request_utils.py index 36d2b12ec3d5..21c4767156ae 100644 --- a/openedx/core/lib/request_utils.py +++ b/openedx/core/lib/request_utils.py @@ -13,10 +13,12 @@ from opaque_keys.edx.keys import CourseKey from rest_framework.views import exception_handler +from openedx.core.constants import CAPTURED_CLEAN_COURSE_ID_PATTERN, POSTFIXED_PATTERNS_TO_NEGATE from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # accommodates course api urls, excluding any course api routes that do not fall under v*/courses, such as v1/blocks. COURSE_REGEX = re.compile(fr'^(.*?/course(s)?/)(?!v[0-9]+/[^/]+){settings.COURSE_ID_PATTERN}') +CLEANED_COURSE_ID_REGEX = re.compile(f'{CAPTURED_CLEAN_COURSE_ID_PATTERN}{POSTFIXED_PATTERNS_TO_NEGATE}') log = logging.getLogger(__name__) @@ -77,12 +79,16 @@ def course_id_from_url(url): if match is None: return None - course_id = match.group('course_id') if course_id is None: return None + cleaned_course_id = CLEANED_COURSE_ID_REGEX.match(course_id) + if cleaned_course_id: + cleaned_course_id = cleaned_course_id.group('course_id') + if cleaned_course_id: + course_id = cleaned_course_id try: return CourseKey.from_string(course_id) except InvalidKeyError: diff --git a/openedx/core/lib/tests/test_request_utils.py b/openedx/core/lib/tests/test_request_utils.py index 3eedea756bde..804f49d96ade 100644 --- a/openedx/core/lib/tests/test_request_utils.py +++ b/openedx/core/lib/tests/test_request_utils.py @@ -95,6 +95,12 @@ def test_course_id_from_url(self): course_id = course_id_from_url('/api/courses/v1/courses/edX/maths/2020') self.assertCourseIdFieldsMatch(course_id=course_id, org='edX', course='maths', run='2020') + course_id = course_id_from_url('/enterprise/5d566680-12a8-4b85-89d8-d9eacbf0f9eb/course/edX+math/enroll/') + self.assertCourseIdFieldsMatch(course_id=course_id, org='edX', course='maths', run=None) + + course_id = course_id_from_url('/enterprise/5d566680-12a8-4b85-89d8-d9eacbf0f9eb/course/edX+math+2020/enroll/') + self.assertCourseIdFieldsMatch(course_id=course_id, org='edX', course='maths', run='2020') + def assertCourseIdFieldsMatch(self, course_id, org, course, run): """ Asserts that the passed-in course id matches the specified fields""" assert course_id.org == org