Commit 17f0b440 by Calen Pennington

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

This commit adds custom mongoengine fields for CourseKeys and UsageKeys.

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]
parent 7852906c
"""
Custom field types for mongoengine
"""
import mongoengine
from xmodule.modulestore.locations import SlashSeparatedCourseKey, Location
from types import NoneType
from xmodule.modulestore.keys import CourseKey
class CourseKeyField(mongoengine.StringField):
"""
Serializes and deserializes CourseKey's to mongo dbs which use mongoengine
"""
def __init__(self, **kwargs):
# it'd be useful to add init args such as support_deprecated, force_deprecated
super(CourseKeyField, self).__init__(**kwargs)
def to_mongo(self, course_key):
"""
For now saves the course key in the deprecated form
"""
assert isinstance(course_key, (NoneType, SlashSeparatedCourseKey))
if course_key:
# don't call super as base.BaseField.to_mongo calls to_python() for some odd reason
return course_key.to_deprecated_string()
else:
return None
def to_python(self, course_key):
"""
Deserialize to a CourseKey instance
"""
# calling super b/c it decodes utf (and doesn't have circularity of from_python)
course_key = super(CourseKeyField, self).to_python(course_key)
assert isinstance(course_key, (NoneType, basestring, SlashSeparatedCourseKey))
if course_key == '':
return None
if isinstance(course_key, basestring):
return SlashSeparatedCourseKey.from_deprecated_string(course_key)
else:
return course_key
def validate(self, value):
assert isinstance(value, (NoneType, basestring, SlashSeparatedCourseKey))
if isinstance(value, CourseKey):
return super(CourseKeyField, self).validate(value.to_deprecated_string())
else:
return super(CourseKeyField, self).validate(value)
def prepare_query_value(self, _opt, value):
return self.to_mongo(value)
class UsageKeyField(mongoengine.StringField):
"""
Represent a UsageKey as a single string in Mongo
"""
def to_mongo(self, location):
"""
For now saves the usage key in the deprecated location i4x/c4x form
"""
assert isinstance(location, (NoneType, SlashSeparatedCourseKey))
if location is None:
return location
return super(UsageKeyField, self).to_mongo(location.to_deprecated_string())
def to_python(self, location):
"""
Deserialize to a UsageKey instance: for now it's a location missing the run
"""
assert isinstance(location, (NoneType, basestring, Location))
if location == '':
return None
if isinstance(location, basestring):
location = super(UsageKeyField, self).to_python(location)
return Location.from_deprecated_string(location)
else:
return location
def validate(self, value):
assert isinstance(value, (NoneType, basestring, Location))
if isinstance(value, Location):
return super(UsageKeyField, self).validate(value.to_deprecated_string())
else:
return super(UsageKeyField, self).validate(value)
def prepare_query_value(self, _opt, value):
return self.to_mongo(value)
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