Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Adds url negation regex for course id #36028

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion openedx/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_key_string>[^/+]+(/|\+)[^/+]+(/|\+)[^/?]+)'
COURSE_ID_PATTERN = COURSE_KEY_PATTERN.replace('course_key_string', 'course_id')
COURSE_KEY_REGEX = COURSE_KEY_PATTERN.replace('P<course_key_string>', ':')

# 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_id>.*?)'

COURSE_PUBLISHED = 'published'
COURSE_UNPUBLISHED = 'unpublished'
8 changes: 7 additions & 1 deletion openedx/core/lib/request_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions openedx/core/lib/tests/test_request_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading