Commit 57f7271b by Calen Pennington

Use the Django TestClient for courseware unit tests, so that middleware is cleaned up properly

parent 437b249d
...@@ -30,7 +30,6 @@ from courseware.tests.factories import ( ...@@ -30,7 +30,6 @@ from courseware.tests.factories import (
) )
import courseware.views.views as views import courseware.views.views as views
from courseware.tests.helpers import LoginEnrollmentTestCase from courseware.tests.helpers import LoginEnrollmentTestCase
from edxmako.tests import mako_middleware_process_request
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from student.models import CourseEnrollment from student.models import CourseEnrollment
from student.roles import CourseCcxCoachRole from student.roles import CourseCcxCoachRole
...@@ -137,21 +136,13 @@ class CoachAccessTestCaseCCX(SharedModuleStoreTestCase, LoginEnrollmentTestCase) ...@@ -137,21 +136,13 @@ class CoachAccessTestCaseCCX(SharedModuleStoreTestCase, LoginEnrollmentTestCase)
CourseEnrollment.enroll(student, ccx_locator) CourseEnrollment.enroll(student, ccx_locator)
# Test for access of a coach # Test for access of a coach
request = self.request_factory.get(reverse('about_course', args=[unicode(ccx_locator)])) resp = self.client.get(reverse('student_progress', args=[unicode(ccx_locator), student.id]))
request.user = self.coach
mako_middleware_process_request(request)
resp = views.progress(request, course_id=unicode(ccx_locator), student_id=student.id)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
# Assert access of a student # Assert access of a student
request = self.request_factory.get(reverse('about_course', args=[unicode(ccx_locator)])) self.client.login(username=student.username, password='test')
request.user = student resp = self.client.get(reverse('student_progress', args=[unicode(ccx_locator), self.coach.id]))
mako_middleware_process_request(request) self.assertEqual(resp.status_code, 404)
with self.assertRaises(Http404) as context:
views.progress(request, course_id=unicode(ccx_locator), student_id=self.coach.id)
self.assertIsNotNone(context.exception)
@attr('shard_1') @attr('shard_1')
......
...@@ -43,7 +43,6 @@ from courseware.tests.factories import StudentModuleFactory, GlobalStaffFactory ...@@ -43,7 +43,6 @@ from courseware.tests.factories import StudentModuleFactory, GlobalStaffFactory
from courseware.url_helpers import get_redirect_url from courseware.url_helpers import get_redirect_url
from courseware.user_state_client import DjangoXBlockUserStateClient from courseware.user_state_client import DjangoXBlockUserStateClient
from courseware.views.index import render_accordion, CoursewareIndex from courseware.views.index import render_accordion, CoursewareIndex
from edxmako.tests import mako_middleware_process_request
from lms.djangoapps.commerce.utils import EcommerceService # pylint: disable=import-error from lms.djangoapps.commerce.utils import EcommerceService # pylint: disable=import-error
from milestones.tests.utils import MilestonesTestCaseMixin from milestones.tests.utils import MilestonesTestCaseMixin
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
...@@ -242,15 +241,13 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -242,15 +241,13 @@ class ViewsTestCase(ModuleStoreTestCase):
self.enrollment = CourseEnrollment.enroll(self.user, self.course_key) self.enrollment = CourseEnrollment.enroll(self.user, self.course_key)
self.enrollment.created = self.date self.enrollment.created = self.date
self.enrollment.save() self.enrollment.save()
self.request_factory = RequestFactory()
chapter = 'Overview' chapter = 'Overview'
self.chapter_url = '%s/%s/%s' % ('/courses', self.course_key, chapter) self.chapter_url = '%s/%s/%s' % ('/courses', self.course_key, chapter)
self.org = u"ꜱᴛᴀʀᴋ ɪɴᴅᴜꜱᴛʀɪᴇꜱ" self.org = u"ꜱᴛᴀʀᴋ ɪɴᴅᴜꜱᴛʀɪᴇꜱ"
self.org_html = "<p>'+Stark/Industries+'</p>" self.org_html = "<p>'+Stark/Industries+'</p>"
self.request = self.request_factory.get("foo") self.assertTrue(self.client.login(username=self.user.username, password=self.password))
self.request.user = self.user
# refresh the course from the modulestore so that it has children # refresh the course from the modulestore so that it has children
self.course = modulestore().get_course(self.course.id) self.course = modulestore().get_course(self.course.id)
...@@ -290,7 +287,6 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -290,7 +287,6 @@ class ViewsTestCase(ModuleStoreTestCase):
Verifies the response when the courseware index page is accessed with Verifies the response when the courseware index page is accessed with
the given chapter and section names. the given chapter and section names.
""" """
self.client.login(username=self.user.username, password=self.password)
url = reverse( url = reverse(
'courseware_section', 'courseware_section',
kwargs={ kwargs={
...@@ -304,7 +300,6 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -304,7 +300,6 @@ class ViewsTestCase(ModuleStoreTestCase):
return response return response
def test_index_no_visible_section_in_chapter(self): def test_index_no_visible_section_in_chapter(self):
self.client.login(username=self.user.username, password=self.password)
# reload the chapter from the store so its children information is updated # reload the chapter from the store so its children information is updated
self.chapter = self.store.get_item(self.chapter.location) self.chapter = self.store.get_item(self.chapter.location)
...@@ -328,7 +323,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -328,7 +323,7 @@ class ViewsTestCase(ModuleStoreTestCase):
Create global staff user and log them in Create global staff user and log them in
""" """
self.global_staff = GlobalStaffFactory.create() # pylint: disable=attribute-defined-outside-init self.global_staff = GlobalStaffFactory.create() # pylint: disable=attribute-defined-outside-init
self.client.login(username=self.global_staff.username, password='test') self.assertTrue(self.client.login(username=self.global_staff.username, password='test'))
def _create_url_for_enroll_staff(self): def _create_url_for_enroll_staff(self):
""" """
...@@ -428,25 +423,22 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -428,25 +423,22 @@ class ViewsTestCase(ModuleStoreTestCase):
in_cart_span = '<span class="add-to-cart">' in_cart_span = '<span class="add-to-cart">'
# don't mock this course due to shopping cart existence checking # don't mock this course due to shopping cart existence checking
course = CourseFactory.create(org="new", number="unenrolled", display_name="course") course = CourseFactory.create(org="new", number="unenrolled", display_name="course")
request = self.request_factory.get(reverse('about_course', args=[unicode(course.id)]))
request.user = AnonymousUser()
# Set up the edxmako middleware for this request to create the RequestContext self.client.logout()
mako_middleware_process_request(request) response = self.client.get(reverse('about_course', args=[unicode(course.id)]))
response = views.course_about(request, unicode(course.id))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertNotIn(in_cart_span, response.content) self.assertNotIn(in_cart_span, response.content)
# authenticated user with nothing in cart # authenticated user with nothing in cart
request.user = self.user self.assertTrue(self.client.login(username=self.user.username, password=self.password))
response = views.course_about(request, unicode(course.id)) response = self.client.get(reverse('about_course', args=[unicode(course.id)]))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertNotIn(in_cart_span, response.content) self.assertNotIn(in_cart_span, response.content)
# now add the course to the cart # now add the course to the cart
cart = shoppingcart.models.Order.get_cart_for_user(self.user) cart = shoppingcart.models.Order.get_cart_for_user(self.user)
shoppingcart.models.PaidCourseRegistration.add_to_order(cart, course.id) shoppingcart.models.PaidCourseRegistration.add_to_order(cart, course.id)
response = views.course_about(request, unicode(course.id)) response = self.client.get(reverse('about_course', args=[unicode(course.id)]))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertIn(in_cart_span, response.content) self.assertIn(in_cart_span, response.content)
...@@ -468,19 +460,18 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -468,19 +460,18 @@ class ViewsTestCase(ModuleStoreTestCase):
course = CourseFactory.create() course = CourseFactory.create()
CourseModeFactory(mode_slug=CourseMode.PROFESSIONAL, course_id=course.id, sku=sku, min_price=1) CourseModeFactory(mode_slug=CourseMode.PROFESSIONAL, course_id=course.id, sku=sku, min_price=1)
request = self.request_factory.get(reverse('about_course', args=[unicode(course.id)])) if is_anonymous:
request.user = AnonymousUser() if is_anonymous else self.user self.client.logout()
else:
# Set up the edxmako middleware for this request to create the RequestContext self.assertTrue(self.client.login(username=self.user.username, password=self.password))
mako_middleware_process_request(request)
# Generate the course about page content
response = views.course_about(request, unicode(course.id))
# Construct the link according the following scenarios and verify its presence in the response: # Construct the link according the following scenarios and verify its presence in the response:
# (1) shopping cart is enabled and the user is not logged in # (1) shopping cart is enabled and the user is not logged in
# (2) shopping cart is enabled and the user is logged in # (2) shopping cart is enabled and the user is logged in
href = '<a href="{uri_stem}?sku={sku}" class="add-to-cart">'.format(uri_stem=checkout_page, sku=sku) href = '<a href="{uri_stem}?sku={sku}" class="add-to-cart">'.format(uri_stem=checkout_page, sku=sku)
# Generate the course about page content
response = self.client.get(reverse('about_course', args=[unicode(course.id)]))
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertIn(href, response.content) self.assertIn(href, response.content)
...@@ -489,7 +480,6 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -489,7 +480,6 @@ class ViewsTestCase(ModuleStoreTestCase):
if not is_anonymous: if not is_anonymous:
self.assert_enrollment_link_present(is_anonymous=is_anonymous) self.assert_enrollment_link_present(is_anonymous=is_anonymous)
else: else:
request = self.request_factory.get("foo")
self.assertEqual(EcommerceService().is_enabled(AnonymousUser()), False) self.assertEqual(EcommerceService().is_enabled(AnonymousUser()), False)
@ddt.data(True, False) @ddt.data(True, False)
...@@ -504,7 +494,6 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -504,7 +494,6 @@ class ViewsTestCase(ModuleStoreTestCase):
if not is_anonymous: if not is_anonymous:
self.assert_enrollment_link_present(is_anonymous=is_anonymous) self.assert_enrollment_link_present(is_anonymous=is_anonymous)
else: else:
request = self.request_factory.get("foo")
self.assertEqual(EcommerceService().is_enabled(AnonymousUser()), False) self.assertEqual(EcommerceService().is_enabled(AnonymousUser()), False)
def test_user_groups(self): def test_user_groups(self):
...@@ -553,7 +542,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -553,7 +542,7 @@ class ViewsTestCase(ModuleStoreTestCase):
self.section.location.name, self.section.location.name,
'f' 'f'
]) ])
self.client.login(username=self.user.username, password=self.password) self.assertTrue(self.client.login(username=self.user.username, password=self.password))
response = self.client.get(request_url) response = self.client.get(request_url)
self.assertEqual(response.status_code, 404) self.assertEqual(response.status_code, 404)
...@@ -566,7 +555,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -566,7 +555,7 @@ class ViewsTestCase(ModuleStoreTestCase):
self.section.location.name, self.section.location.name,
'1' '1'
] ]
self.client.login(username=self.user.username, password=self.password) self.assertTrue(self.client.login(username=self.user.username, password=self.password))
for idx, val in enumerate(url_parts): for idx, val in enumerate(url_parts):
url_parts_copy = url_parts[:] url_parts_copy = url_parts[:]
url_parts_copy[idx] = val + u'χ' url_parts_copy[idx] = val + u'χ'
...@@ -595,9 +584,8 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -595,9 +584,8 @@ class ViewsTestCase(ModuleStoreTestCase):
def test_jump_to_invalid(self): def test_jump_to_invalid(self):
# TODO add a test for invalid location # TODO add a test for invalid location
# TODO add a test for no data * # TODO add a test for no data *
request = self.request_factory.get(self.chapter_url) response = self.client.get(reverse('jump_to', args=['foo/bar/baz', 'baz']))
self.assertRaisesRegexp(Http404, 'Invalid course_key or usage_key', views.jump_to, self.assertEquals(response.status_code, 404)
request, 'bar', ())
@unittest.skip @unittest.skip
def test_no_end_on_about_page(self): def test_no_end_on_about_page(self):
...@@ -623,13 +611,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -623,13 +611,7 @@ class ViewsTestCase(ModuleStoreTestCase):
If `expected_end_text` is None, verifies that the about page *does not* contain the text If `expected_end_text` is None, verifies that the about page *does not* contain the text
"Classes End". "Classes End".
""" """
request = self.request_factory.get("foo") result = self.client.get(reverse('about_course', args=[unicode(course.id)]))
request.user = self.user
# TODO: Remove the dependency on MakoMiddleware (by making the views explicitly supply a RequestContext)
mako_middleware_process_request(request)
result = views.course_about(request, course_id)
if expected_end_text is not None: if expected_end_text is not None:
self.assertContains(result, "Classes End") self.assertContains(result, "Classes End")
self.assertContains(result, expected_end_text) self.assertContains(result, expected_end_text)
...@@ -640,7 +622,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -640,7 +622,7 @@ class ViewsTestCase(ModuleStoreTestCase):
# log into a staff account # log into a staff account
admin = AdminFactory() admin = AdminFactory()
self.client.login(username=admin.username, password='test') self.assertTrue(self.client.login(username=admin.username, password='test'))
url = reverse('submission_history', kwargs={ url = reverse('submission_history', kwargs={
'course_id': unicode(self.course_key), 'course_id': unicode(self.course_key),
...@@ -655,7 +637,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -655,7 +637,7 @@ class ViewsTestCase(ModuleStoreTestCase):
# log into a staff account # log into a staff account
admin = AdminFactory() admin = AdminFactory()
self.client.login(username=admin.username, password='test') self.assertTrue(self.client.login(username=admin.username, password='test'))
# try it with an existing user and a malicious location # try it with an existing user and a malicious location
url = reverse('submission_history', kwargs={ url = reverse('submission_history', kwargs={
...@@ -679,7 +661,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -679,7 +661,7 @@ class ViewsTestCase(ModuleStoreTestCase):
# log into a staff account # log into a staff account
admin = AdminFactory.create() admin = AdminFactory.create()
self.client.login(username=admin.username, password='test') self.assertTrue(self.client.login(username=admin.username, password='test'))
usage_key = self.course_key.make_usage_key('problem', 'test-history') usage_key = self.course_key.make_usage_key('problem', 'test-history')
state_client = DjangoXBlockUserStateClient(admin) state_client = DjangoXBlockUserStateClient(admin)
...@@ -733,7 +715,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -733,7 +715,7 @@ class ViewsTestCase(ModuleStoreTestCase):
course_key = course.id course_key = course.id
client = Client() client = Client()
admin = AdminFactory.create() admin = AdminFactory.create()
client.login(username=admin.username, password='test') self.assertTrue(client.login(username=admin.username, password='test'))
state_client = DjangoXBlockUserStateClient(admin) state_client = DjangoXBlockUserStateClient(admin)
usage_key = course_key.make_usage_key('problem', 'test-history') usage_key = course_key.make_usage_key('problem', 'test-history')
state_client.set( state_client.set(
...@@ -766,7 +748,6 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -766,7 +748,6 @@ class ViewsTestCase(ModuleStoreTestCase):
self.assertNotContains(response, checkbox_html, html=True) self.assertNotContains(response, checkbox_html, html=True)
def test_financial_assistance_page(self): def test_financial_assistance_page(self):
self.client.login(username=self.user.username, password=self.password)
url = reverse('financial_assistance') url = reverse('financial_assistance')
response = self.client.get(url) response = self.client.get(url)
# This is a static page, so just assert that it is returned correctly # This is a static page, so just assert that it is returned correctly
...@@ -796,7 +777,6 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -796,7 +777,6 @@ class ViewsTestCase(ModuleStoreTestCase):
) )
CourseEnrollmentFactory(course_id=course, user=self.user, mode=mode) CourseEnrollmentFactory(course_id=course, user=self.user, mode=mode)
self.client.login(username=self.user.username, password=self.password)
url = reverse('financial_assistance_form') url = reverse('financial_assistance_form')
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
...@@ -815,7 +795,6 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -815,7 +795,6 @@ class ViewsTestCase(ModuleStoreTestCase):
def _submit_financial_assistance_form(self, data): def _submit_financial_assistance_form(self, data):
"""Submit a financial assistance request.""" """Submit a financial assistance request."""
self.client.login(username=self.user.username, password=self.password)
url = reverse('submit_financial_assistance_request') url = reverse('submit_financial_assistance_request')
return self.client.post(url, json.dumps(data), content_type='application/json') return self.client.post(url, json.dumps(data), content_type='application/json')
...@@ -898,53 +877,38 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -898,53 +877,38 @@ class ViewsTestCase(ModuleStoreTestCase):
reverse('financial_assistance_form'), reverse('financial_assistance_form'),
reverse('submit_financial_assistance_request') reverse('submit_financial_assistance_request')
): ):
self.client.logout()
response = self.client.get(url) response = self.client.get(url)
self.assertRedirects(response, reverse('signin_user') + '?next=' + url) self.assertRedirects(response, reverse('signin_user') + '?next=' + url)
def test_bypass_course_info(self): def test_bypass_course_info(self):
course_id = unicode(self.course_key) course_id = unicode(self.course_key)
request = self.request_factory.get(
reverse('info', args=[course_id])
)
# Middleware is not supported by the request factory. Simulate a
# logged-in user by setting request.user manually.
request.user = self.user
# Set up the edxmako middleware for this request to create the RequestContext
mako_middleware_process_request(request)
self.assertFalse(self.course.bypass_home) self.assertFalse(self.course.bypass_home)
self.assertIsNone(request.META.get('HTTP_REFERER')) # pylint: disable=no-member response = self.client.get(reverse('info', args=[course_id]))
response = views.course_info(request, course_id)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
request.META['HTTP_REFERER'] = reverse('dashboard') # pylint: disable=no-member response = self.client.get(reverse('info', args=[course_id]), HTTP_REFERER=reverse('dashboard'))
response = views.course_info(request, course_id)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.course.bypass_home = True self.course.bypass_home = True
self.store.update_item(self.course, self.user.id) # pylint: disable=no-member self.store.update_item(self.course, self.user.id) # pylint: disable=no-member
self.assertTrue(self.course.bypass_home) self.assertTrue(self.course.bypass_home)
response = views.course_info(request, course_id) response = self.client.get(reverse('info', args=[course_id]), HTTP_REFERER=reverse('dashboard'))
# assertRedirects would be great here, but it forces redirections to be absolute URLs. self.assertRedirects(response, reverse('courseware', args=[course_id]), fetch_redirect_response=False)
self.assertEqual(response.status_code, 302)
self.assertEqual(
response.url,
reverse('courseware', args=[course_id])
)
request.META['HTTP_REFERER'] = 'foo' # pylint: disable=no-member response = self.client.get(reverse('info', args=[course_id]), HTTP_REFERER='foo')
response = views.course_info(request, course_id)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
def test_accordion(self): def test_accordion(self):
request = RequestFactory().get('foo')
request.user = self.user
table_of_contents = toc_for_course( table_of_contents = toc_for_course(
self.request.user, request.user,
self.request, request,
self.course, self.course,
unicode(self.course.get_children()[0].scope_ids.usage_id), unicode(self.course.get_children()[0].scope_ids.usage_id),
None, None,
...@@ -952,7 +916,7 @@ class ViewsTestCase(ModuleStoreTestCase): ...@@ -952,7 +916,7 @@ class ViewsTestCase(ModuleStoreTestCase):
) )
# removes newlines and whitespace from the returned view string # removes newlines and whitespace from the returned view string
view = ''.join(render_accordion(self.request, self.course, table_of_contents['chapters']).split()) view = ''.join(render_accordion(request, self.course, table_of_contents['chapters']).split())
# the course id unicode is re-encoded here because the quote function does not accept unicode # the course id unicode is re-encoded here because the quote function does not accept unicode
course_id = quote(unicode(self.course.id).encode("utf-8")) course_id = quote(unicode(self.course.id).encode("utf-8"))
...@@ -978,7 +942,7 @@ class BaseDueDateTests(ModuleStoreTestCase): ...@@ -978,7 +942,7 @@ class BaseDueDateTests(ModuleStoreTestCase):
""" """
__test__ = False __test__ = False
def get_text(self, course): def get_response(self, course):
"""Return the rendered text for the page to be verified""" """Return the rendered text for the page to be verified"""
raise NotImplementedError raise NotImplementedError
...@@ -1005,10 +969,8 @@ class BaseDueDateTests(ModuleStoreTestCase): ...@@ -1005,10 +969,8 @@ class BaseDueDateTests(ModuleStoreTestCase):
def setUp(self): def setUp(self):
super(BaseDueDateTests, self).setUp() super(BaseDueDateTests, self).setUp()
self.request_factory = RequestFactory()
self.user = UserFactory.create() self.user = UserFactory.create()
self.request = self.request_factory.get("foo") self.assertTrue(self.client.login(username=self.user.username, password='test'))
self.request.user = self.user
self.time_with_tz = "due Sep 18, 2013 at 11:30 UTC" self.time_with_tz = "due Sep 18, 2013 at 11:30 UTC"
self.time_without_tz = "due Sep 18, 2013 at 11:30" self.time_without_tz = "due Sep 18, 2013 at 11:30"
...@@ -1019,50 +981,50 @@ class BaseDueDateTests(ModuleStoreTestCase): ...@@ -1019,50 +981,50 @@ class BaseDueDateTests(ModuleStoreTestCase):
# in course_module's init method, the date_display_format will be set accordingly to # in course_module's init method, the date_display_format will be set accordingly to
# remove the timezone. # remove the timezone.
course = self.set_up_course(due_date_display_format=None, show_timezone=False) course = self.set_up_course(due_date_display_format=None, show_timezone=False)
text = self.get_text(course) response = self.get_response(course)
self.assertIn(self.time_without_tz, text) self.assertContains(response, self.time_without_tz)
self.assertNotIn(self.time_with_tz, text) self.assertNotContains(response, self.time_with_tz)
# Test that show_timezone has been cleared (which means you get the default value of True). # Test that show_timezone has been cleared (which means you get the default value of True).
self.assertTrue(course.show_timezone) self.assertTrue(course.show_timezone)
def test_defaults(self): def test_defaults(self):
course = self.set_up_course() course = self.set_up_course()
text = self.get_text(course) response = self.get_response(course)
self.assertIn(self.time_with_tz, text) self.assertContains(response, self.time_with_tz)
def test_format_none(self): def test_format_none(self):
# Same for setting the due date to None # Same for setting the due date to None
course = self.set_up_course(due_date_display_format=None) course = self.set_up_course(due_date_display_format=None)
text = self.get_text(course) response = self.get_response(course)
self.assertIn(self.time_with_tz, text) self.assertContains(response, self.time_with_tz)
def test_format_plain_text(self): def test_format_plain_text(self):
# plain text due date # plain text due date
course = self.set_up_course(due_date_display_format="foobar") course = self.set_up_course(due_date_display_format="foobar")
text = self.get_text(course) response = self.get_response(course)
self.assertNotIn(self.time_with_tz, text) self.assertNotContains(response, self.time_with_tz)
self.assertIn("due foobar", text) self.assertContains(response, "due foobar")
def test_format_date(self): def test_format_date(self):
# due date with no time # due date with no time
course = self.set_up_course(due_date_display_format=u"%b %d %y") course = self.set_up_course(due_date_display_format=u"%b %d %y")
text = self.get_text(course) response = self.get_response(course)
self.assertNotIn(self.time_with_tz, text) self.assertNotContains(response, self.time_with_tz)
self.assertIn("due Sep 18 13", text) self.assertContains(response, "due Sep 18 13")
def test_format_hidden(self): def test_format_hidden(self):
# hide due date completely # hide due date completely
course = self.set_up_course(due_date_display_format=u"") course = self.set_up_course(due_date_display_format=u"")
text = self.get_text(course) response = self.get_response(course)
self.assertNotIn("due ", text) self.assertNotContains(response, "due ")
def test_format_invalid(self): def test_format_invalid(self):
# improperly formatted due_date_display_format falls through to default # improperly formatted due_date_display_format falls through to default
# (value of show_timezone does not matter-- setting to False to make that clear). # (value of show_timezone does not matter-- setting to False to make that clear).
course = self.set_up_course(due_date_display_format=u"%%%", show_timezone=False) course = self.set_up_course(due_date_display_format=u"%%%", show_timezone=False)
text = self.get_text(course) response = self.get_response(course)
self.assertNotIn("%%%", text) self.assertNotContains(response, "%%%")
self.assertIn(self.time_with_tz, text) self.assertContains(response, self.time_with_tz)
class TestProgressDueDate(BaseDueDateTests): class TestProgressDueDate(BaseDueDateTests):
...@@ -1071,12 +1033,9 @@ class TestProgressDueDate(BaseDueDateTests): ...@@ -1071,12 +1033,9 @@ class TestProgressDueDate(BaseDueDateTests):
""" """
__test__ = True __test__ = True
def get_text(self, course): def get_response(self, course):
""" Returns the HTML for the progress page """ """ Returns the HTML for the progress page """
return self.client.get(reverse('progress', args=[unicode(course.id)]))
# Set up the edxmako middleware for this request to create the RequestContext
mako_middleware_process_request(self.request)
return views.progress(self.request, course_id=unicode(course.id), student_id=self.user.id).content
class TestAccordionDueDate(BaseDueDateTests): class TestAccordionDueDate(BaseDueDateTests):
...@@ -1085,12 +1044,9 @@ class TestAccordionDueDate(BaseDueDateTests): ...@@ -1085,12 +1044,9 @@ class TestAccordionDueDate(BaseDueDateTests):
""" """
__test__ = True __test__ = True
def get_text(self, course): def get_response(self, course):
""" Returns the HTML for the accordion """ """ Returns the HTML for the accordion """
table_of_contents = toc_for_course( return self.client.get(reverse('courseware', args=[unicode(course.id)]), follow=True)
self.request.user, self.request, course, unicode(course.get_children()[0].scope_ids.usage_id), None, None
)
return render_accordion(self.request, course, table_of_contents['chapters'])
@attr('shard_1') @attr('shard_1')
...@@ -1102,13 +1058,7 @@ class StartDateTests(ModuleStoreTestCase): ...@@ -1102,13 +1058,7 @@ class StartDateTests(ModuleStoreTestCase):
def setUp(self): def setUp(self):
super(StartDateTests, self).setUp() super(StartDateTests, self).setUp()
self.request_factory = RequestFactory()
self.user = UserFactory.create() self.user = UserFactory.create()
self.request = self.request_factory.get("foo")
# Set up the edxmako middleware for this request to create the RequestContext
mako_middleware_process_request(self.request)
self.request.user = self.user
def set_up_course(self): def set_up_course(self):
""" """
...@@ -1120,12 +1070,11 @@ class StartDateTests(ModuleStoreTestCase): ...@@ -1120,12 +1070,11 @@ class StartDateTests(ModuleStoreTestCase):
course = modulestore().get_course(course.id) course = modulestore().get_course(course.id)
return course return course
def get_about_text(self, course_key): def get_about_response(self, course_key):
""" """
Get the text of the /about page for the course. Get the text of the /about page for the course.
""" """
text = views.course_about(self.request, unicode(course_key)).content return self.client.get(reverse('about_course', args=[unicode(course_key)]))
return text
@patch('util.date_utils.pgettext', fake_pgettext(translations={ @patch('util.date_utils.pgettext', fake_pgettext(translations={
("abbreviated month name", "Sep"): "SEPTEMBER", ("abbreviated month name", "Sep"): "SEPTEMBER",
...@@ -1135,9 +1084,9 @@ class StartDateTests(ModuleStoreTestCase): ...@@ -1135,9 +1084,9 @@ class StartDateTests(ModuleStoreTestCase):
})) }))
def test_format_localized_in_studio_course(self): def test_format_localized_in_studio_course(self):
course = self.set_up_course() course = self.set_up_course()
text = self.get_about_text(course.id) response = self.get_about_response(course.id)
# The start date is set in the set_up_course function above. # The start date is set in the set_up_course function above.
self.assertIn("2013-SEPTEMBER-16", text) self.assertContains(response, "2013-SEPTEMBER-16")
@patch('util.date_utils.pgettext', fake_pgettext(translations={ @patch('util.date_utils.pgettext', fake_pgettext(translations={
("abbreviated month name", "Jul"): "JULY", ("abbreviated month name", "Jul"): "JULY",
...@@ -1147,9 +1096,9 @@ class StartDateTests(ModuleStoreTestCase): ...@@ -1147,9 +1096,9 @@ class StartDateTests(ModuleStoreTestCase):
})) }))
@unittest.skip @unittest.skip
def test_format_localized_in_xml_course(self): def test_format_localized_in_xml_course(self):
text = self.get_about_text(SlashSeparatedCourseKey('edX', 'toy', 'TT_2012_Fall')) response = self.get_about_response(SlashSeparatedCourseKey('edX', 'toy', 'TT_2012_Fall'))
# The start date is set in common/test/data/two_toys/policies/TT_2012_Fall/policy.json # The start date is set in common/test/data/two_toys/policies/TT_2012_Fall/policy.json
self.assertIn("2015-JULY-17", text) self.assertContains(response, "2015-JULY-17")
@attr('shard_1') @attr('shard_1')
...@@ -1163,13 +1112,8 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1163,13 +1112,8 @@ class ProgressPageTests(ModuleStoreTestCase):
def setUp(self): def setUp(self):
super(ProgressPageTests, self).setUp() super(ProgressPageTests, self).setUp()
self.request_factory = RequestFactory()
self.user = UserFactory.create() self.user = UserFactory.create()
self.request = self.request_factory.get("foo") self.assertTrue(self.client.login(username=self.user.username, password='test'))
self.request.user = self.user
# Set up the edxmako middleware for this request to create the RequestContext
mako_middleware_process_request(self.request)
self.setup_course() self.setup_course()
...@@ -1193,7 +1137,9 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1193,7 +1137,9 @@ class ProgressPageTests(ModuleStoreTestCase):
""" """
Test that XSS attack is prevented Test that XSS attack is prevented
""" """
resp = views.progress(self.request, course_id=unicode(self.course.id), student_id=self.user.id) resp = self.client.get(
reverse('student_progress', args=[unicode(self.course.id), self.user.id])
)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
# Test that malicious code does not appear in html # Test that malicious code does not appear in html
self.assertNotIn(malicious_code, resp.content) self.assertNotIn(malicious_code, resp.content)
...@@ -1201,7 +1147,9 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1201,7 +1147,9 @@ class ProgressPageTests(ModuleStoreTestCase):
def test_pure_ungraded_xblock(self): def test_pure_ungraded_xblock(self):
ItemFactory.create(category='acid', parent_location=self.vertical.location) ItemFactory.create(category='acid', parent_location=self.vertical.location)
resp = views.progress(self.request, course_id=unicode(self.course.id)) resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) @ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
...@@ -1212,7 +1160,9 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1212,7 +1160,9 @@ class ProgressPageTests(ModuleStoreTestCase):
""" """
# Create new course with respect to 'default_store' # Create new course with respect to 'default_store'
# Enroll student into course
self.course = CourseFactory.create(default_store=default_store) self.course = CourseFactory.create(default_store=default_store)
CourseEnrollmentFactory(user=self.user, course_id=self.course.id, mode=CourseMode.HONOR)
# Invalid Student Ids (Integer and Non-int) # Invalid Student Ids (Integer and Non-int)
invalid_student_ids = [ invalid_student_ids = [
...@@ -1220,16 +1170,15 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1220,16 +1170,15 @@ class ProgressPageTests(ModuleStoreTestCase):
'azU3N_8$', 'azU3N_8$',
] ]
for invalid_id in invalid_student_ids: for invalid_id in invalid_student_ids:
self.assertRaises(
Http404, views.progress, resp = self.client.get(
self.request, reverse('student_progress', args=[unicode(self.course.id), invalid_id])
course_id=unicode(self.course.id),
student_id=invalid_id
) )
self.assertEquals(resp.status_code, 404)
# Enroll student into course resp = self.client.get(
CourseEnrollment.enroll(self.user, self.course.id) reverse('student_progress', args=[unicode(self.course.id), self.user.id])
resp = views.progress(self.request, course_id=unicode(self.course.id), student_id=self.user.id) )
# Assert that valid 'student_id' returns 200 status # Assert that valid 'student_id' returns 200 status
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
...@@ -1244,7 +1193,8 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1244,7 +1193,8 @@ class ProgressPageTests(ModuleStoreTestCase):
# Create a new course, a user which will not be enrolled in course, admin user for staff access # Create a new course, a user which will not be enrolled in course, admin user for staff access
course = CourseFactory.create(default_store=default_store) course = CourseFactory.create(default_store=default_store)
not_enrolled_user = UserFactory.create() not_enrolled_user = UserFactory.create()
self.request.user = AdminFactory.create() admin = AdminFactory.create()
self.assertTrue(self.client.login(username=admin.username, password='test'))
# Create and enable Credit course # Create and enable Credit course
CreditCourse.objects.create(course_key=course.id, enabled=True) CreditCourse.objects.create(course_key=course.id, enabled=True)
...@@ -1265,25 +1215,38 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1265,25 +1215,38 @@ class ProgressPageTests(ModuleStoreTestCase):
# Add a single credit requirement (final grade) # Add a single credit requirement (final grade)
set_credit_requirements(course.id, requirements) set_credit_requirements(course.id, requirements)
resp = views.progress(self.request, course_id=unicode(course.id), student_id=not_enrolled_user.id) resp = self.client.get(
reverse('student_progress', args=[unicode(course.id), not_enrolled_user.id])
)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
def test_non_ascii_grade_cutoffs(self): def test_non_ascii_grade_cutoffs(self):
resp = views.progress(self.request, course_id=unicode(self.course.id)) resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
def test_generate_cert_config(self): def test_generate_cert_config(self):
resp = views.progress(self.request, course_id=unicode(self.course.id))
resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertNotContains(resp, 'Request Certificate') self.assertNotContains(resp, 'Request Certificate')
# Enable the feature, but do not enable it for this course # Enable the feature, but do not enable it for this course
CertificateGenerationConfiguration(enabled=True).save() CertificateGenerationConfiguration(enabled=True).save()
resp = views.progress(self.request, course_id=unicode(self.course.id))
resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertNotContains(resp, 'Request Certificate') self.assertNotContains(resp, 'Request Certificate')
# Enable certificate generation for this course # Enable certificate generation for this course
certs_api.set_cert_generation_enabled(self.course.id, True) certs_api.set_cert_generation_enabled(self.course.id, True)
resp = views.progress(self.request, course_id=unicode(self.course.id))
resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertNotContains(resp, 'Request Certificate') self.assertNotContains(resp, 'Request Certificate')
@patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': True}) @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': True})
...@@ -1326,7 +1289,9 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1326,7 +1289,9 @@ class ProgressPageTests(ModuleStoreTestCase):
self.course.save() self.course.save()
self.store.update_item(self.course, self.user.id) self.store.update_item(self.course, self.user.id)
resp = views.progress(self.request, course_id=unicode(self.course.id)) resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertContains(resp, u"View Certificate") self.assertContains(resp, u"View Certificate")
self.assertContains(resp, u"You can keep working for a higher grade") self.assertContains(resp, u"You can keep working for a higher grade")
...@@ -1337,7 +1302,9 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1337,7 +1302,9 @@ class ProgressPageTests(ModuleStoreTestCase):
certificates[0]['is_active'] = False certificates[0]['is_active'] = False
self.store.update_item(self.course, self.user.id) self.store.update_item(self.course, self.user.id)
resp = views.progress(self.request, course_id=unicode(self.course.id)) resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertNotContains(resp, u"View Your Certificate") self.assertNotContains(resp, u"View Your Certificate")
self.assertNotContains(resp, u"You can now view your certificate") self.assertNotContains(resp, u"You can now view your certificate")
self.assertContains(resp, u"We're creating your certificate.") self.assertContains(resp, u"We're creating your certificate.")
...@@ -1364,11 +1331,13 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1364,11 +1331,13 @@ class ProgressPageTests(ModuleStoreTestCase):
# Enable certificate generation for this course # Enable certificate generation for this course
certs_api.set_cert_generation_enabled(self.course.id, True) certs_api.set_cert_generation_enabled(self.course.id, True)
resp = views.progress(self.request, course_id=unicode(self.course.id)) resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertContains(resp, u"Download Your Certificate") self.assertContains(resp, u"Download Your Certificate")
@ddt.data( @ddt.data(
*itertools.product(((41, 4, True), (41, 4, False)), (True, False)) *itertools.product(((55, 4, True), (55, 4, False)), (True, False))
) )
@ddt.unpack @ddt.unpack
def test_query_counts(self, (sql_calls, mongo_calls, self_paced), self_paced_enabled): def test_query_counts(self, (sql_calls, mongo_calls, self_paced), self_paced_enabled):
...@@ -1376,7 +1345,9 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1376,7 +1345,9 @@ class ProgressPageTests(ModuleStoreTestCase):
SelfPacedConfiguration(enabled=self_paced_enabled).save() SelfPacedConfiguration(enabled=self_paced_enabled).save()
self.setup_course(self_paced=self_paced) self.setup_course(self_paced=self_paced)
with self.assertNumQueries(sql_calls), check_mongo_calls(mongo_calls): with self.assertNumQueries(sql_calls), check_mongo_calls(mongo_calls):
resp = views.progress(self.request, course_id=unicode(self.course.id)) resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)
@patch('courseware.grades.grade', Mock(return_value={ @patch('courseware.grades.grade', Mock(return_value={
...@@ -1405,7 +1376,9 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -1405,7 +1376,9 @@ class ProgressPageTests(ModuleStoreTestCase):
'lms.djangoapps.verify_student.models.SoftwareSecurePhotoVerification.user_is_verified' 'lms.djangoapps.verify_student.models.SoftwareSecurePhotoVerification.user_is_verified'
) as user_verify: ) as user_verify:
user_verify.return_value = user_verified user_verify.return_value = user_verified
resp = views.progress(self.request, course_id=unicode(self.course.id)) resp = self.client.get(
reverse('progress', args=[unicode(self.course.id)])
)
cert_button_hidden = course_mode is CourseMode.AUDIT or \ cert_button_hidden = course_mode is CourseMode.AUDIT or \
course_mode in CourseMode.VERIFIED_MODES and not user_verified course_mode in CourseMode.VERIFIED_MODES and not user_verified
...@@ -1503,8 +1476,7 @@ class GenerateUserCertTests(ModuleStoreTestCase): ...@@ -1503,8 +1476,7 @@ class GenerateUserCertTests(ModuleStoreTestCase):
grade_cutoffs={'cutoff': 0.75, 'Pass': 0.5} grade_cutoffs={'cutoff': 0.75, 'Pass': 0.5}
) )
self.enrollment = CourseEnrollment.enroll(self.student, self.course.id, mode='honor') self.enrollment = CourseEnrollment.enroll(self.student, self.course.id, mode='honor')
self.request = RequestFactory() self.assertTrue(self.client.login(username=self.student, password='123456'))
self.client.login(username=self.student, password='123456')
self.url = reverse('generate_user_cert', kwargs={'course_id': unicode(self.course.id)}) self.url = reverse('generate_user_cert', kwargs={'course_id': unicode(self.course.id)})
def test_user_with_out_passing_grades(self): def test_user_with_out_passing_grades(self):
...@@ -1671,7 +1643,8 @@ class TestIndexView(ModuleStoreTestCase): ...@@ -1671,7 +1643,8 @@ class TestIndexView(ModuleStoreTestCase):
CourseEnrollmentFactory(user=user, course_id=course.id) CourseEnrollmentFactory(user=user, course_id=course.id)
request = RequestFactory().get( self.assertTrue(self.client.login(username=user.username, password='test'))
response = self.client.get(
reverse( reverse(
'courseware_section', 'courseware_section',
kwargs={ kwargs={
...@@ -1681,15 +1654,8 @@ class TestIndexView(ModuleStoreTestCase): ...@@ -1681,15 +1654,8 @@ class TestIndexView(ModuleStoreTestCase):
} }
) )
) )
request.user = user
# Set up the edxmako middleware for this request to create the RequestContext
mako_middleware_process_request(request)
# Trigger the assertions embedded in the ViewCheckerBlocks # Trigger the assertions embedded in the ViewCheckerBlocks
response = CoursewareIndex.as_view()(
request, unicode(course.id), chapter=chapter.url_name, section=section.url_name
)
self.assertEquals(response.content.count("ViewCheckerPassed"), 3) self.assertEquals(response.content.count("ViewCheckerPassed"), 3)
@XBlock.register_temp_plugin(ActivateIDCheckerBlock, 'id_checker') @XBlock.register_temp_plugin(ActivateIDCheckerBlock, 'id_checker')
...@@ -1704,7 +1670,8 @@ class TestIndexView(ModuleStoreTestCase): ...@@ -1704,7 +1670,8 @@ class TestIndexView(ModuleStoreTestCase):
CourseEnrollmentFactory(user=user, course_id=course.id) CourseEnrollmentFactory(user=user, course_id=course.id)
request = RequestFactory().get( self.assertTrue(self.client.login(username=user.username, password='test'))
response = self.client.get(
reverse( reverse(
'courseware_section', 'courseware_section',
kwargs={ kwargs={
...@@ -1714,14 +1681,6 @@ class TestIndexView(ModuleStoreTestCase): ...@@ -1714,14 +1681,6 @@ class TestIndexView(ModuleStoreTestCase):
} }
) + '?activate_block_id=test_block_id' ) + '?activate_block_id=test_block_id'
) )
request.user = user
# Set up the edxmako middleware for this request to create the RequestContext
mako_middleware_process_request(request)
response = CoursewareIndex.as_view()(
request, unicode(course.id), chapter=chapter.url_name, section=section.url_name
)
self.assertIn("Activate Block ID: test_block_id", response.content) self.assertIn("Activate Block ID: test_block_id", response.content)
...@@ -1818,7 +1777,8 @@ class TestIndexViewWithGating(ModuleStoreTestCase, MilestonesTestCaseMixin): ...@@ -1818,7 +1777,8 @@ class TestIndexViewWithGating(ModuleStoreTestCase, MilestonesTestCaseMixin):
""" """
Test index view with a gated sequential raises Http404 Test index view with a gated sequential raises Http404
""" """
request = RequestFactory().get( self.assertTrue(self.client.login(username=self.user.username, password='test'))
response = self.client.get(
reverse( reverse(
'courseware_section', 'courseware_section',
kwargs={ kwargs={
...@@ -1828,18 +1788,8 @@ class TestIndexViewWithGating(ModuleStoreTestCase, MilestonesTestCaseMixin): ...@@ -1828,18 +1788,8 @@ class TestIndexViewWithGating(ModuleStoreTestCase, MilestonesTestCaseMixin):
} }
) )
) )
request.user = self.user
# Set up the edxmako middleware for this request to create the RequestContext
mako_middleware_process_request(request)
with self.assertRaises(Http404): self.assertEquals(response.status_code, 404)
CoursewareIndex.as_view()(
request,
unicode(self.course.id),
chapter=self.chapter.url_name,
section=self.gated_seq.url_name
)
class TestRenderXBlock(RenderXBlockTestMixin, ModuleStoreTestCase): class TestRenderXBlock(RenderXBlockTestMixin, ModuleStoreTestCase):
......
...@@ -658,7 +658,6 @@ def course_about(request, course_id): ...@@ -658,7 +658,6 @@ def course_about(request, course_id):
@ensure_valid_course_key @ensure_valid_course_key
def progress(request, course_id, student_id=None): def progress(request, course_id, student_id=None):
""" Display the progress page. """ """ Display the progress page. """
course_key = CourseKey.from_string(course_id) course_key = CourseKey.from_string(course_id)
with modulestore().bulk_operations(course_key): with modulestore().bulk_operations(course_key):
...@@ -673,6 +672,14 @@ def _progress(request, course_key, student_id): ...@@ -673,6 +672,14 @@ def _progress(request, course_key, student_id):
Course staff are allowed to see the progress of students in their class. Course staff are allowed to see the progress of students in their class.
""" """
if student_id is not None:
try:
student_id = int(student_id)
# Check for ValueError if 'student_id' cannot be converted to integer.
except ValueError:
raise Http404
course = get_course_with_access(request.user, 'load', course_key, depth=None, check_if_enrolled=True) course = get_course_with_access(request.user, 'load', course_key, depth=None, check_if_enrolled=True)
# check to see if there is a required survey that must be taken before # check to see if there is a required survey that must be taken before
...@@ -697,8 +704,7 @@ def _progress(request, course_key, student_id): ...@@ -697,8 +704,7 @@ def _progress(request, course_key, student_id):
raise Http404 raise Http404
try: try:
student = User.objects.get(id=student_id) student = User.objects.get(id=student_id)
# Check for ValueError if 'student_id' cannot be converted to integer. except User.DoesNotExist:
except (ValueError, User.DoesNotExist):
raise Http404 raise Http404
# NOTE: To make sure impersonation by instructor works, use # NOTE: To make sure impersonation by instructor works, use
......
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