Commit d8464dbf by Ayub-khan

-changed method name from "from_string_or_404" to "course_key_from_string_or_404".

-Updated method "course_key_from_string_or_404" to raise message too.
-Wrote tests for "course_key_from_string_or_404" when exception message is given.
-Modified existing methods to use "ddt.data".
-Used Splunk logs to find exectly where we were getting "Invalid Key Error"
-Updated Views where we were getting "Invalid Key Error" in splunk logs.
-Wrote tests for those View End points where we were getting "Invalid Key Error"
parent a2c686cf
...@@ -14,7 +14,8 @@ from edxmako.shortcuts import render_to_response ...@@ -14,7 +14,8 @@ from edxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore import ModuleStoreEnum
from xmodule.tabs import CourseTabList, CourseTab, InvalidTabsException, StaticTab from xmodule.tabs import CourseTabList, CourseTab, InvalidTabsException, StaticTab
from opaque_keys.edx.keys import CourseKey, UsageKey from opaque_keys.edx.keys import UsageKey
from util.course_key_utils import course_key_from_string_or_404
from ..utils import get_lms_link_for_item from ..utils import get_lms_link_for_item
...@@ -39,7 +40,7 @@ def tabs_handler(request, course_key_string): ...@@ -39,7 +40,7 @@ def tabs_handler(request, course_key_string):
Creating a tab, deleting a tab, or changing its contents is not supported through this method. Creating a tab, deleting a tab, or changing its contents is not supported through this method.
Instead use the general xblock URL (see item.xblock_handler). Instead use the general xblock URL (see item.xblock_handler).
""" """
course_key = CourseKey.from_string(course_key_string) course_key = course_key_from_string_or_404(course_key_string)
if not has_course_author_access(request.user, course_key): if not has_course_author_access(request.user, course_key):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -10,6 +10,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory ...@@ -10,6 +10,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.tabs import CourseTabList from xmodule.tabs import CourseTabList
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from django.http import Http404
class TabsPageTests(CourseTestCase): class TabsPageTests(CourseTestCase):
...@@ -191,6 +192,13 @@ class TabsPageTests(CourseTestCase): ...@@ -191,6 +192,13 @@ class TabsPageTests(CourseTestCase):
self.assertIn('<span class="sr">Delete this component</span>', html) self.assertIn('<span class="sr">Delete this component</span>', html)
self.assertIn('<span data-tooltip="Drag to reorder" class="drag-handle action"></span>', html) self.assertIn('<span data-tooltip="Drag to reorder" class="drag-handle action"></span>', html)
def test_invalid_course_id(self):
""" Asserts that Http404 is raised when the course id is not valid. """
invalid_tab_url = reverse_course_url('tabs_handler', "/some.invalid.key/TTT/CS01/2015_T0")
with self.assertRaises(Http404):
self.client.get(invalid_tab_url)
class PrimitiveTabEdit(ModuleStoreTestCase): class PrimitiveTabEdit(ModuleStoreTestCase):
"""Tests for the primitive tab edit data manipulations""" """Tests for the primitive tab edit data manipulations"""
......
...@@ -9,6 +9,7 @@ from django.contrib.auth.models import User ...@@ -9,6 +9,7 @@ from django.contrib.auth.models import User
from student.models import CourseEnrollment from student.models import CourseEnrollment
from student.roles import CourseStaffRole, CourseInstructorRole from student.roles import CourseStaffRole, CourseInstructorRole
from student import auth from student import auth
from django.http import Http404
class UsersTestCase(CourseTestCase): class UsersTestCase(CourseTestCase):
...@@ -315,3 +316,12 @@ class UsersTestCase(CourseTestCase): ...@@ -315,3 +316,12 @@ class UsersTestCase(CourseTestCase):
CourseEnrollment.is_enrolled(self.ext_user, self.course.id), CourseEnrollment.is_enrolled(self.ext_user, self.course.id),
'User ext_user should have been enrolled in the course' 'User ext_user should have been enrolled in the course'
) )
def test_invalid_course_id(self):
""" Asserts that Http404 is raised when the course id is not valid. """
wrong_url = reverse_course_url(
'course_team_handler', "/some.invalid.key/TTT/CS01/2015_T0",
kwargs={'email': self.ext_user.email}
)
with self.assertRaises(Http404):
self.client.get(wrong_url)
...@@ -8,7 +8,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie ...@@ -8,7 +8,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie
from edxmako.shortcuts import render_to_response from edxmako.shortcuts import render_to_response
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from opaque_keys.edx.keys import CourseKey from util.course_key_utils import course_key_from_string_or_404
from opaque_keys.edx.locator import LibraryLocator from opaque_keys.edx.locator import LibraryLocator
from util.json_request import JsonResponse, expect_json from util.json_request import JsonResponse, expect_json
from student.roles import CourseInstructorRole, CourseStaffRole, LibraryUserRole from student.roles import CourseInstructorRole, CourseStaffRole, LibraryUserRole
...@@ -49,7 +49,7 @@ def course_team_handler(request, course_key_string=None, email=None): ...@@ -49,7 +49,7 @@ def course_team_handler(request, course_key_string=None, email=None):
DELETE: DELETE:
json: remove a particular course team member from the course team (email is required). json: remove a particular course team member from the course team (email is required).
""" """
course_key = CourseKey.from_string(course_key_string) if course_key_string else None course_key = course_key_from_string_or_404(course_key_string) if course_key_string else None
# No permissions check here - each helper method does its own check. # No permissions check here - each helper method does its own check.
if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'): if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'):
......
...@@ -6,14 +6,15 @@ from opaque_keys import InvalidKeyError ...@@ -6,14 +6,15 @@ from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
def from_string_or_404(course_key_string): def course_key_from_string_or_404(course_key_string, message=None):
""" """
Gets CourseKey from the string passed as parameter. Gets CourseKey from the string passed as parameter.
Parses course key from string(containing course key) or raises 404 if the string's format is invalid. Parses course key from string(containing course key) or raises 404 if the string's format is invalid.
Arguments: Arguments:
course_key_string(str): It is string containing the course key course_key_string(str): It contains the course key
message(str): It contains the exception message
Returns: Returns:
CourseKey: A key that uniquely identifies a course CourseKey: A key that uniquely identifies a course
...@@ -25,6 +26,6 @@ def from_string_or_404(course_key_string): ...@@ -25,6 +26,6 @@ def from_string_or_404(course_key_string):
try: try:
course_key = CourseKey.from_string(course_key_string) course_key = CourseKey.from_string(course_key_string)
except InvalidKeyError: except InvalidKeyError:
raise Http404 raise Http404(message)
return course_key return course_key
\ No newline at end of file
""" """
Tests for util.course_key_utils Tests for util.course_key_utils
""" """
from nose.tools import assert_equals, assert_raises # pylint: disable=no-name-in-module from util.course_key_utils import course_key_from_string_or_404
from util.course_key_utils import from_string_or_404
from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.keys import CourseKey
from django.http import Http404 from django.http import Http404
import ddt
import unittest
def test_from_string_or_404(): @ddt.ddt
class TestFromStringOr404(unittest.TestCase):
#testing with split style course keys """
assert_raises( Base Test class for course_key_from_string_or_404 utility tests
Http404, """
from_string_or_404, @ddt.data(
"/some.invalid.key/course-v1:TTT+CS01+2015_T0" ("/some.invalid.key/course-v1:TTT+CS01+2015_T0", "course-v1:TTT+CS01+2015_T0"), # split style course keys
) ("/some.invalid.key/TTT/CS01/2015_T0", "TTT/CS01/2015_T0"), # mongo style course keys
assert_equals(
CourseKey.from_string("course-v1:TTT+CS01+2015_T0"),
from_string_or_404("course-v1:TTT+CS01+2015_T0")
) )
def test_from_string_or_404(self, (invalid_course_key, valid_course_key)):
"""
Tests course_key_from_string_or_404 for valid and invalid split style course keys and mongo style course keys.
"""
self.assertRaises(
Http404,
course_key_from_string_or_404,
invalid_course_key,
)
self.assertEquals(
CourseKey.from_string(valid_course_key),
course_key_from_string_or_404(valid_course_key)
)
#testing with mongo style course keys @ddt.data(
assert_raises( "/some.invalid.key/course-v1:TTT+CS01+2015_T0", # split style invalid course key
Http404, "/some.invalid.key/TTT/CS01/2015_T0" # mongo style invalid course key
from_string_or_404,
"/some.invalid.key/TTT/CS01/2015_T0"
)
assert_equals(
CourseKey.from_string("TTT/CS01/2015_T0"),
from_string_or_404("TTT/CS01/2015_T0")
) )
def test_from_string_or_404_with_message(self, course_string):
"""
Tests course_key_from_string_or_404 with exception message for split style and monog style invalid course keys.
:return:
"""
try:
course_key_from_string_or_404(course_string, message="Invalid Keys")
except Http404 as exception:
self.assertEquals(str(exception), "Invalid Keys")
\ No newline at end of file
...@@ -1312,6 +1312,14 @@ class InlineDiscussionUnicodeTestCase(SharedModuleStoreTestCase, UnicodeTestMixi ...@@ -1312,6 +1312,14 @@ class InlineDiscussionUnicodeTestCase(SharedModuleStoreTestCase, UnicodeTestMixi
self.assertEqual(response_data["discussion_data"][0]["title"], text) self.assertEqual(response_data["discussion_data"][0]["title"], text)
self.assertEqual(response_data["discussion_data"][0]["body"], text) self.assertEqual(response_data["discussion_data"][0]["body"], text)
def _test_invalid_course_id(self):
""" Asserts that Http404 is raised when the course id is not valid. """
request = RequestFactory().get("dummy_url")
request.user = self.student
with self.assertRaises(Http404):
views.inline_discussion(
request, self.course.id.to_deprecated_string(), self.course.discussion_topics['General']['id']
)
class ForumFormDiscussionUnicodeTestCase(SharedModuleStoreTestCase, UnicodeTestMixin): class ForumFormDiscussionUnicodeTestCase(SharedModuleStoreTestCase, UnicodeTestMixin):
@classmethod @classmethod
......
...@@ -40,7 +40,7 @@ from django_comment_client.utils import ( ...@@ -40,7 +40,7 @@ from django_comment_client.utils import (
import django_comment_client.utils as utils import django_comment_client.utils as utils
import lms.lib.comment_client as cc import lms.lib.comment_client as cc
from opaque_keys.edx.keys import CourseKey from util.course_key_utils import course_key_from_string_or_404
THREADS_PER_PAGE = 20 THREADS_PER_PAGE = 20
INLINE_THREADS_PER_PAGE = 20 INLINE_THREADS_PER_PAGE = 20
...@@ -178,7 +178,7 @@ def use_bulk_ops(view_func): ...@@ -178,7 +178,7 @@ def use_bulk_ops(view_func):
""" """
@wraps(view_func) @wraps(view_func)
def wrapped_view(request, course_id, *args, **kwargs): # pylint: disable=missing-docstring def wrapped_view(request, course_id, *args, **kwargs): # pylint: disable=missing-docstring
course_key = CourseKey.from_string(course_id) course_key = course_key_from_string_or_404(course_id)
with modulestore().bulk_operations(course_key): with modulestore().bulk_operations(course_key):
return view_func(request, course_key, *args, **kwargs) return view_func(request, course_key, *args, **kwargs)
return wrapped_view return wrapped_view
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment