Make course ids and usage ids opaque to LMS and Studio [partial commit]

This commit updates common/djangoapps.

These keys are now objects with a limited interface, and the particular
internal representation is managed by the data storage layer (the
modulestore).

For the LMS, there should be no outward-facing changes to the system.
The keys are, for now, a change to internal representation only. For
Studio, the new serialized form of the keys is used in urls, to allow
for further migration in the future.

Co-Author: Andy Armstrong <andya@edx.org>
Co-Author: Christina Roberts <christina@edx.org>
Co-Author: David Baumgold <db@edx.org>
Co-Author: Diana Huang <dkh@edx.org>
Co-Author: Don Mitchell <dmitchell@edx.org>
Co-Author: Julia Hansbrough <julia@edx.org>
Co-Author: Nimisha Asthagiri <nasthagiri@edx.org>
Co-Author: Sarina Canelake <sarina@edx.org>

[LMS-2370]
This commit is contained in:
Calen Pennington
2014-04-30 10:17:43 -04:00
parent 7852906ce0
commit e2bfcf2a36
42 changed files with 603 additions and 330 deletions

View File

@@ -19,6 +19,7 @@ from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, mixed_store_config
from xmodule.modulestore.inheritance import own_metadata
from xmodule.modulestore.django import editable_modulestore
from xmodule.modulestore.locations import SlashSeparatedCourseKey
from external_auth.models import ExternalAuthMap
from external_auth.views import shib_login, course_specific_login, course_specific_register, _flatten_to_ascii
@@ -340,8 +341,8 @@ class ShibSPTest(ModuleStoreTestCase):
'?course_id=MITx/999/course/Robot_Super_Course' +
'&enrollment_action=enroll')
login_response = course_specific_login(login_request, 'MITx/999/Robot_Super_Course')
reg_response = course_specific_register(login_request, 'MITx/999/Robot_Super_Course')
login_response = course_specific_login(login_request, SlashSeparatedCourseKey('MITx', '999', 'Robot_Super_Course'))
reg_response = course_specific_register(login_request, SlashSeparatedCourseKey('MITx', '999', 'Robot_Super_Course'))
if "shib" in domain:
self.assertIsInstance(login_response, HttpResponseRedirect)
@@ -375,8 +376,8 @@ class ShibSPTest(ModuleStoreTestCase):
'?course_id=DNE/DNE/DNE/Robot_Super_Course' +
'&enrollment_action=enroll')
login_response = course_specific_login(login_request, 'DNE/DNE/DNE')
reg_response = course_specific_register(login_request, 'DNE/DNE/DNE')
login_response = course_specific_login(login_request, SlashSeparatedCourseKey('DNE', 'DNE', 'DNE'))
reg_response = course_specific_register(login_request, SlashSeparatedCourseKey('DNE', 'DNE', 'DNE'))
self.assertIsInstance(login_response, HttpResponseRedirect)
self.assertEqual(login_response['Location'],
@@ -436,7 +437,7 @@ class ShibSPTest(ModuleStoreTestCase):
for student in [shib_student, other_ext_student, int_student]:
request = self.request_factory.post('/change_enrollment')
request.POST.update({'enrollment_action': 'enroll',
'course_id': course.id})
'course_id': course.id.to_deprecated_string()})
request.user = student
response = change_enrollment(request)
# If course is not limited or student has correct shib extauth then enrollment should be allowed
@@ -476,7 +477,7 @@ class ShibSPTest(ModuleStoreTestCase):
self.assertFalse(CourseEnrollment.is_enrolled(student, course.id))
self.client.logout()
request_kwargs = {'path': '/shib-login/',
'data': {'enrollment_action': 'enroll', 'course_id': course.id, 'next': '/testredirect'},
'data': {'enrollment_action': 'enroll', 'course_id': course.id.to_deprecated_string(), 'next': '/testredirect'},
'follow': False,
'REMOTE_USER': 'testuser@stanford.edu',
'Shib-Identity-Provider': 'https://idp.stanford.edu/'}

View File

@@ -3,8 +3,6 @@ Provides unit tests for SSL based authentication portions
of the external_auth app.
"""
import logging
import StringIO
import unittest
from django.conf import settings
@@ -22,7 +20,7 @@ from edxmako.middleware import MakoMiddleware
from external_auth.models import ExternalAuthMap
import external_auth.views
from student.tests.factories import UserFactory
from xmodule.modulestore.exceptions import InsufficientSpecificationError
from opaque_keys import InvalidKeyError
FEATURES_WITH_SSL_AUTH = settings.FEATURES.copy()
FEATURES_WITH_SSL_AUTH['AUTH_USE_CERTIFICATES'] = True
@@ -193,18 +191,23 @@ class SSLClientTest(TestCase):
This tests to make sure when immediate signup is on that
the user doesn't get presented with the registration page.
"""
# Expect a NotImplementError from course page as we don't have anything else built
with self.assertRaisesRegexp(InsufficientSpecificationError,
'Must provide one of url, version_guid, package_id'):
# Expect an InvalidKeyError from course page as we don't have anything else built
with self.assertRaisesRegexp(
InvalidKeyError,
"<class 'xmodule.modulestore.keys.CourseKey'>: None"
):
self.client.get(
reverse('signup'), follow=True,
SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL))
SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL)
)
# assert that we are logged in
self.assertIn(SESSION_KEY, self.client.session)
# Now that we are logged in, make sure we don't see the registration page
with self.assertRaisesRegexp(InsufficientSpecificationError,
'Must provide one of url, version_guid, package_id'):
with self.assertRaisesRegexp(
InvalidKeyError,
"<class 'xmodule.modulestore.keys.CourseKey'>: None"
):
self.client.get(reverse('signup'), follow=True)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@@ -228,7 +231,6 @@ class SSLClientTest(TestCase):
self.assertIn(reverse('dashboard'), response['location'])
self.assertIn(SESSION_KEY, self.client.session)
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@override_settings(FEATURES=FEATURES_WITH_SSL_AUTH_IMMEDIATE_SIGNUP)
def test_ssl_bad_eamap(self):

View File

@@ -576,9 +576,8 @@ def course_specific_login(request, course_id):
Dispatcher function for selecting the specific login method
required by the course
"""
try:
course = course_from_id(course_id)
except ItemNotFoundError:
course = student.views.course_from_id(course_id)
if not course:
# couldn't find the course, will just return vanilla signin page
return _redirect_with_get_querydict('signin_user', request.GET)
@@ -595,9 +594,9 @@ def course_specific_register(request, course_id):
Dispatcher function for selecting the specific registration method
required by the course
"""
try:
course = course_from_id(course_id)
except ItemNotFoundError:
course = student.views.course_from_id(course_id)
if not course:
# couldn't find the course, will just return vanilla registration page
return _redirect_with_get_querydict('register_user', request.GET)
@@ -934,9 +933,3 @@ def provider_xrds(request):
# custom XRDS header necessary for discovery process
response['X-XRDS-Location'] = get_xrds_url('xrds', request)
return response
def course_from_id(course_id):
"""Return the CourseDescriptor corresponding to this course_id"""
course_loc = CourseDescriptor.id_to_location(course_id)
return modulestore().get_instance(course_id, course_loc)