Merge pull request #2137 from abdoosh00/feature/unicode
Unicode changes to support R to L script
This commit is contained in:
@@ -143,7 +143,7 @@ def get_lms_link_for_item(location, preview=False, course_id=None):
|
||||
else:
|
||||
lms_base = settings.LMS_BASE
|
||||
|
||||
lms_link = "//{lms_base}/courses/{course_id}/jump_to/{location}".format(
|
||||
lms_link = u"//{lms_base}/courses/{course_id}/jump_to/{location}".format(
|
||||
lms_base=lms_base,
|
||||
course_id=course_id,
|
||||
location=Location(location)
|
||||
@@ -179,7 +179,7 @@ def get_lms_link_for_about_page(location):
|
||||
about_base = None
|
||||
|
||||
if about_base is not None:
|
||||
lms_link = "//{about_base_url}/courses/{course_id}/about".format(
|
||||
lms_link = u"//{about_base_url}/courses/{course_id}/about".format(
|
||||
about_base_url=about_base,
|
||||
course_id=Location(location).course_id
|
||||
)
|
||||
|
||||
@@ -267,8 +267,7 @@ def unit_handler(request, tag=None, package_id=None, branch=None, version_guid=N
|
||||
preview_lms_base = settings.FEATURES.get('PREVIEW_LMS_BASE')
|
||||
|
||||
preview_lms_link = (
|
||||
'//{preview_lms_base}/courses/{org}/{course}/'
|
||||
'{course_name}/courseware/{section}/{subsection}/{index}'
|
||||
u'//{preview_lms_base}/courses/{org}/{course}/{course_name}/courseware/{section}/{subsection}/{index}'
|
||||
).format(
|
||||
preview_lms_base=preview_lms_base,
|
||||
lms_base=settings.LMS_BASE,
|
||||
|
||||
@@ -251,7 +251,7 @@ def create_new_course(request):
|
||||
run = request.json.get('run')
|
||||
|
||||
try:
|
||||
dest_location = Location('i4x', org, number, 'course', run)
|
||||
dest_location = Location(u'i4x', org, number, u'course', run)
|
||||
except InvalidLocationError as error:
|
||||
return JsonResponse({
|
||||
"ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(
|
||||
@@ -286,8 +286,10 @@ def create_new_course(request):
|
||||
course_search_location = bson.son.SON({
|
||||
'_id.tag': 'i4x',
|
||||
# cannot pass regex to Location constructor; thus this hack
|
||||
'_id.org': re.compile('^{}$'.format(dest_location.org), re.IGNORECASE),
|
||||
'_id.course': re.compile('^{}$'.format(dest_location.course), re.IGNORECASE),
|
||||
# pylint: disable=E1101
|
||||
'_id.org': re.compile(u'^{}$'.format(dest_location.org), re.IGNORECASE | re.UNICODE),
|
||||
# pylint: disable=E1101
|
||||
'_id.course': re.compile(u'^{}$'.format(dest_location.course), re.IGNORECASE | re.UNICODE),
|
||||
'_id.category': 'course',
|
||||
})
|
||||
courses = modulestore().collection.find(course_search_location, fields=('_id'))
|
||||
|
||||
@@ -41,7 +41,7 @@ def handler_prefix(block, handler='', suffix=''):
|
||||
Trailing `/`s are removed from the returned url.
|
||||
"""
|
||||
return reverse('preview_handler', kwargs={
|
||||
'usage_id': quote_slashes(str(block.scope_ids.usage_id)),
|
||||
'usage_id': quote_slashes(unicode(block.scope_ids.usage_id).encode('utf-8')),
|
||||
'handler': handler,
|
||||
'suffix': suffix,
|
||||
}).rstrip('/?')
|
||||
|
||||
@@ -84,8 +84,8 @@ require(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
|
||||
if (required) {
|
||||
return required;
|
||||
}
|
||||
if (item !== encodeURIComponent(item)) {
|
||||
return gettext('Please do not use any spaces or special characters in this field.');
|
||||
if (/\s/g.test(item)) {
|
||||
return gettext('Please do not use any spaces in this field.');
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
@@ -164,7 +164,7 @@ require(["domReady!", "jquery", "js/models/module_info", "coffee/src/views/unit"
|
||||
% endif
|
||||
${_("with the subsection {link_start}{name}{link_end}").format(
|
||||
name=subsection.display_name_with_default,
|
||||
link_start='<a href="{url}">'.format(url=subsection_url),
|
||||
link_start=u'<a href="{url}">'.format(url=subsection_url),
|
||||
link_end='</a>',
|
||||
)}
|
||||
</p>
|
||||
|
||||
@@ -110,12 +110,12 @@ def instance_key(model, instance_or_pk):
|
||||
|
||||
|
||||
def set_cached_content(content):
|
||||
cache.set(str(content.location), content)
|
||||
cache.set(unicode(content.location).encode("utf-8"), content)
|
||||
|
||||
|
||||
def get_cached_content(location):
|
||||
return cache.get(str(location))
|
||||
return cache.get(unicode(location).encode("utf-8"))
|
||||
|
||||
|
||||
def del_cached_content(location):
|
||||
cache.delete(str(location))
|
||||
cache.delete(unicode(location).encode("utf-8"))
|
||||
|
||||
@@ -77,7 +77,7 @@ def is_commentable_cohorted(course_id, commentable_id):
|
||||
# inline discussions are cohorted by default
|
||||
ans = True
|
||||
|
||||
log.debug("is_commentable_cohorted({0}, {1}) = {2}".format(course_id,
|
||||
log.debug(u"is_commentable_cohorted({0}, {1}) = {2}".format(course_id,
|
||||
commentable_id,
|
||||
ans))
|
||||
return ans
|
||||
|
||||
@@ -19,7 +19,7 @@ def _url_replace_regex(prefix):
|
||||
To anyone contemplating making this more complicated:
|
||||
http://xkcd.com/1171/
|
||||
"""
|
||||
return r"""
|
||||
return ur"""
|
||||
(?x) # flags=re.VERBOSE
|
||||
(?P<quote>\\?['"]) # the opening quotes
|
||||
(?P<prefix>{prefix}) # the prefix
|
||||
@@ -152,7 +152,7 @@ def replace_static_urls(text, data_directory, course_id=None, static_asset_path=
|
||||
return "".join([quote, url, quote])
|
||||
|
||||
return re.sub(
|
||||
_url_replace_regex('(?:{static_url}|/static/)(?!{data_dir})'.format(
|
||||
_url_replace_regex(u'(?:{static_url}|/static/)(?!{data_dir})'.format(
|
||||
static_url=settings.STATIC_URL,
|
||||
data_dir=static_asset_path or data_directory
|
||||
)),
|
||||
|
||||
@@ -159,30 +159,30 @@ class CourseRole(GroupBasedRole):
|
||||
|
||||
if isinstance(self.location, Location):
|
||||
try:
|
||||
groupnames.append('{0}_{1}'.format(role, self.location.course_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, self.location.course_id))
|
||||
course_context = self.location.course_id # course_id is valid for translation
|
||||
except InvalidLocationError: # will occur on old locations where location is not of category course
|
||||
if course_context is None:
|
||||
raise CourseContextRequired()
|
||||
else:
|
||||
groupnames.append('{0}_{1}'.format(role, course_context))
|
||||
groupnames.append(u'{0}_{1}'.format(role, course_context))
|
||||
try:
|
||||
locator = loc_mapper().translate_location_to_course_locator(course_context, self.location)
|
||||
groupnames.append('{0}_{1}'.format(role, locator.package_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, locator.package_id))
|
||||
except (InvalidLocationError, ItemNotFoundError):
|
||||
# if it's never been mapped, the auth won't be via the Locator syntax
|
||||
pass
|
||||
# least preferred legacy role_course format
|
||||
groupnames.append('{0}_{1}'.format(role, self.location.course))
|
||||
groupnames.append(u'{0}_{1}'.format(role, self.location.course)) # pylint: disable=E1101, E1103
|
||||
elif isinstance(self.location, CourseLocator):
|
||||
groupnames.append('{0}_{1}'.format(role, self.location.package_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, self.location.package_id))
|
||||
# handle old Location syntax
|
||||
old_location = loc_mapper().translate_locator_to_location(self.location, get_course=True)
|
||||
if old_location:
|
||||
# the slashified version of the course_id (myu/mycourse/myrun)
|
||||
groupnames.append('{0}_{1}'.format(role, old_location.course_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, old_location.course_id))
|
||||
# add the least desirable but sometimes occurring format.
|
||||
groupnames.append('{0}_{1}'.format(role, old_location.course))
|
||||
groupnames.append(u'{0}_{1}'.format(role, old_location.course)) # pylint: disable=E1101, E1103
|
||||
|
||||
super(CourseRole, self).__init__(groupnames)
|
||||
|
||||
@@ -193,12 +193,13 @@ class OrgRole(GroupBasedRole):
|
||||
"""
|
||||
def __init__(self, role, location):
|
||||
location = Location(location)
|
||||
super(OrgRole, self).__init__(['{}_{}'.format(role, location.org)])
|
||||
super(OrgRole, self).__init__([u'{}_{}'.format(role, location.org)])
|
||||
|
||||
|
||||
class CourseStaffRole(CourseRole):
|
||||
"""A Staff member of a course"""
|
||||
ROLE = 'staff'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CourseStaffRole, self).__init__(self.ROLE, *args, **kwargs)
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ def dashboard(request):
|
||||
|
||||
course_enrollment_pairs.append((course, enrollment))
|
||||
except ItemNotFoundError:
|
||||
log.error("User {0} enrolled in non-existent course {1}"
|
||||
log.error(u"User {0} enrolled in non-existent course {1}"
|
||||
.format(user.username, enrollment.course_id))
|
||||
|
||||
course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True)
|
||||
@@ -495,9 +495,9 @@ def change_enrollment(request):
|
||||
org, course_num, run = course_id.split("/")
|
||||
dog_stats_api.increment(
|
||||
"common.student.enrollment",
|
||||
tags=["org:{0}".format(org),
|
||||
"course:{0}".format(course_num),
|
||||
"run:{0}".format(run)]
|
||||
tags=[u"org:{0}".format(org),
|
||||
u"course:{0}".format(course_num),
|
||||
u"run:{0}".format(run)]
|
||||
)
|
||||
|
||||
CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)
|
||||
|
||||
@@ -372,7 +372,7 @@ class LoncapaProblem(object):
|
||||
# TODO: figure out where to get file submissions when rescoring.
|
||||
if 'filesubmission' in responder.allowed_inputfields and student_answers is None:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
raise Exception(_("Cannot rescore problems with possible file submissions"))
|
||||
raise Exception(_(u"Cannot rescore problems with possible file submissions"))
|
||||
|
||||
# use 'student_answers' only if it is provided, and if it might contain a file
|
||||
# submission that would not exist in the persisted "student_answers".
|
||||
|
||||
@@ -50,7 +50,7 @@ class CorrectMap(object):
|
||||
):
|
||||
|
||||
if answer_id is not None:
|
||||
self.cmap[str(answer_id)] = {
|
||||
self.cmap[answer_id] = {
|
||||
'correctness': correctness,
|
||||
'npoints': npoints,
|
||||
'msg': msg,
|
||||
|
||||
@@ -62,7 +62,7 @@ class XQueueInterface(object):
|
||||
"""
|
||||
|
||||
def __init__(self, url, django_auth, requests_auth=None):
|
||||
self.url = url
|
||||
self.url = unicode(url)
|
||||
self.auth = django_auth
|
||||
self.session = requests.Session()
|
||||
self.session.auth = requests_auth
|
||||
|
||||
@@ -34,7 +34,9 @@ class StaticContent(object):
|
||||
|
||||
@staticmethod
|
||||
def generate_thumbnail_name(original_name):
|
||||
return ('{0}' + XASSET_THUMBNAIL_TAIL_NAME).format(os.path.splitext(original_name)[0])
|
||||
return u"{name_root}{extension}".format(
|
||||
name_root=os.path.splitext(original_name)[0],
|
||||
extension=XASSET_THUMBNAIL_TAIL_NAME,)
|
||||
|
||||
@staticmethod
|
||||
def compute_location(org, course, name, revision=None, is_thumbnail=False):
|
||||
@@ -64,7 +66,7 @@ class StaticContent(object):
|
||||
"""
|
||||
Returns a boolean if a path is believed to be a c4x link based on the leading element
|
||||
"""
|
||||
return path_string.startswith('/{0}/'.format(XASSET_LOCATION_TAG))
|
||||
return path_string.startswith(u'/{0}/'.format(XASSET_LOCATION_TAG))
|
||||
|
||||
@staticmethod
|
||||
def renamespace_c4x_path(path_string, target_location):
|
||||
@@ -86,14 +88,14 @@ class StaticContent(object):
|
||||
the actual /c4x/... path which the client needs to reference static content
|
||||
"""
|
||||
if location is not None:
|
||||
return "/static/{name}".format(**location.dict())
|
||||
return u"/static/{name}".format(**location.dict())
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_base_url_path_for_course_assets(loc):
|
||||
if loc is not None:
|
||||
return "/c4x/{org}/{course}/asset".format(**loc.dict())
|
||||
return u"/c4x/{org}/{course}/asset".format(**loc.dict())
|
||||
|
||||
@staticmethod
|
||||
def get_id_from_location(location):
|
||||
@@ -237,6 +239,6 @@ class ContentStore(object):
|
||||
|
||||
except Exception, e:
|
||||
# log and continue as thumbnails are generally considered as optional
|
||||
logging.exception("Failed to generate thumbnail for {0}. Exception: {1}".format(content.location, str(e)))
|
||||
logging.exception(u"Failed to generate thumbnail for {0}. Exception: {1}".format(content.location, str(e)))
|
||||
|
||||
return thumbnail_content, thumbnail_file_location
|
||||
|
||||
@@ -30,12 +30,12 @@ URL_RE = re.compile("""
|
||||
|
||||
# TODO (cpennington): We should decide whether we want to expand the
|
||||
# list of valid characters in a location
|
||||
INVALID_CHARS = re.compile(r"[^\w.-]")
|
||||
INVALID_CHARS = re.compile(r"[^\w.%-]", re.UNICODE)
|
||||
# Names are allowed to have colons.
|
||||
INVALID_CHARS_NAME = re.compile(r"[^\w.:-]")
|
||||
INVALID_CHARS_NAME = re.compile(r"[^\w.:%-]", re.UNICODE)
|
||||
|
||||
# html ids can contain word chars and dashes
|
||||
INVALID_HTML_CHARS = re.compile(r"[^\w-]")
|
||||
INVALID_HTML_CHARS = re.compile(r"[^\w-]", re.UNICODE)
|
||||
|
||||
_LocationBase = namedtuple('LocationBase', 'tag org course category name revision')
|
||||
|
||||
@@ -186,14 +186,14 @@ class Location(_LocationBase):
|
||||
elif isinstance(location, basestring):
|
||||
match = URL_RE.match(location)
|
||||
if match is None:
|
||||
log.debug("location %r doesn't match URL", location)
|
||||
log.debug(u"location %r doesn't match URL", location)
|
||||
raise InvalidLocationError(location)
|
||||
groups = match.groupdict()
|
||||
check_dict(groups)
|
||||
return _LocationBase.__new__(_cls, **groups)
|
||||
elif isinstance(location, (list, tuple)):
|
||||
if len(location) not in (5, 6):
|
||||
log.debug('location has wrong length')
|
||||
log.debug(u'location has wrong length')
|
||||
raise InvalidLocationError(location)
|
||||
|
||||
if len(location) == 5:
|
||||
@@ -216,9 +216,9 @@ class Location(_LocationBase):
|
||||
"""
|
||||
Return a string containing the URL for this location
|
||||
"""
|
||||
url = "{0.tag}://{0.org}/{0.course}/{0.category}/{0.name}".format(self)
|
||||
url = u"{0.tag}://{0.org}/{0.course}/{0.category}/{0.name}".format(self)
|
||||
if self.revision:
|
||||
url += "@" + self.revision
|
||||
url += u"@{rev}".format(rev=self.revision) # pylint: disable=E1101
|
||||
return url
|
||||
|
||||
def html_id(self):
|
||||
@@ -226,7 +226,7 @@ class Location(_LocationBase):
|
||||
Return a string with a version of the location that is safe for use in
|
||||
html id attributes
|
||||
"""
|
||||
id_string = "-".join(str(v) for v in self.list() if v is not None)
|
||||
id_string = u"-".join(v for v in self.list() if v is not None)
|
||||
return Location.clean_for_html(id_string)
|
||||
|
||||
def dict(self):
|
||||
@@ -240,6 +240,9 @@ class Location(_LocationBase):
|
||||
return list(self)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.url().encode("utf-8"))
|
||||
|
||||
def __unicode__(self):
|
||||
return self.url()
|
||||
|
||||
def __repr__(self):
|
||||
@@ -254,7 +257,7 @@ class Location(_LocationBase):
|
||||
Throws an InvalidLocationError is this location does not represent a course.
|
||||
"""
|
||||
if self.category != 'course':
|
||||
raise InvalidLocationError('Cannot call course_id for {0} because it is not of category course'.format(self))
|
||||
raise InvalidLocationError(u'Cannot call course_id for {0} because it is not of category course'.format(self))
|
||||
|
||||
return "/".join([self.org, self.course, self.name])
|
||||
|
||||
|
||||
@@ -88,9 +88,9 @@ class LocMapperStore(object):
|
||||
"""
|
||||
if package_id is None:
|
||||
if course_location.category == 'course':
|
||||
package_id = "{0.org}.{0.course}.{0.name}".format(course_location)
|
||||
package_id = u"{0.org}.{0.course}.{0.name}".format(course_location)
|
||||
else:
|
||||
package_id = "{0.org}.{0.course}".format(course_location)
|
||||
package_id = u"{0.org}.{0.course}".format(course_location)
|
||||
# very like _interpret_location_id but w/o the _id
|
||||
location_id = self._construct_location_son(
|
||||
course_location.org, course_location.course,
|
||||
@@ -185,7 +185,6 @@ class LocMapperStore(object):
|
||||
self._cache_location_map_entry(old_style_course_id, location, published_usage, draft_usage)
|
||||
return result
|
||||
|
||||
|
||||
def translate_locator_to_location(self, locator, get_course=False):
|
||||
"""
|
||||
Returns an old style Location for the given Locator if there's an appropriate entry in the
|
||||
@@ -331,12 +330,12 @@ class LocMapperStore(object):
|
||||
# strip id envelope if any
|
||||
entry_id = entry_id.get('_id', entry_id)
|
||||
if entry_id.get('name', False):
|
||||
return '{0[org]}/{0[course]}/{0[name]}'.format(entry_id)
|
||||
return u'{0[org]}/{0[course]}/{0[name]}'.format(entry_id)
|
||||
elif entry_id.get('_id.org', False):
|
||||
# the odd format one
|
||||
return '{0[_id.org]}/{0[_id.course]}'.format(entry_id)
|
||||
return u'{0[_id.org]}/{0[_id.course]}'.format(entry_id)
|
||||
else:
|
||||
return '{0[org]}/{0[course]}'.format(entry_id)
|
||||
return u'{0[org]}/{0[course]}'.format(entry_id)
|
||||
|
||||
def _construct_location_son(self, org, course, name=None):
|
||||
"""
|
||||
@@ -392,7 +391,7 @@ class LocMapperStore(object):
|
||||
"""
|
||||
See if the location x published pair is in the cache. If so, return the mapped locator.
|
||||
"""
|
||||
entry = self.cache.get('{}+{}'.format(old_course_id, location.url()))
|
||||
entry = self.cache.get(u'{}+{}'.format(old_course_id, location.url()))
|
||||
if entry is not None:
|
||||
if published:
|
||||
return entry[0]
|
||||
@@ -424,7 +423,7 @@ class LocMapperStore(object):
|
||||
See if the package_id is in the cache. If so, return the mapped location to the
|
||||
course root.
|
||||
"""
|
||||
return self.cache.get('courseId+{}'.format(locator_package_id))
|
||||
return self.cache.get(u'courseId+{}'.format(locator_package_id))
|
||||
|
||||
def _cache_course_locator(self, old_course_id, published_course_locator, draft_course_locator):
|
||||
"""
|
||||
@@ -442,9 +441,9 @@ class LocMapperStore(object):
|
||||
"""
|
||||
setmany = {}
|
||||
if location.category == 'course':
|
||||
setmany['courseId+{}'.format(published_usage.package_id)] = location
|
||||
setmany[u'courseId+{}'.format(published_usage.package_id)] = location
|
||||
setmany[unicode(published_usage)] = location
|
||||
setmany[unicode(draft_usage)] = location
|
||||
setmany['{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage)
|
||||
setmany[u'{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage)
|
||||
setmany[old_course_id] = (published_usage, draft_usage)
|
||||
self.cache.set_many(setmany)
|
||||
|
||||
@@ -64,13 +64,13 @@ class Locator(object):
|
||||
'''
|
||||
str(self) returns something like this: "mit.eecs.6002x"
|
||||
'''
|
||||
return unicode(self).encode('utf8')
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
'''
|
||||
unicode(self) returns something like this: "mit.eecs.6002x"
|
||||
'''
|
||||
return self.url()
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
@abstractmethod
|
||||
def version(self):
|
||||
@@ -199,12 +199,12 @@ class CourseLocator(Locator):
|
||||
Return a string representing this location.
|
||||
"""
|
||||
if self.package_id:
|
||||
result = self.package_id
|
||||
result = unicode(self.package_id)
|
||||
if self.branch:
|
||||
result += '/' + BRANCH_PREFIX + self.branch
|
||||
return result
|
||||
elif self.version_guid:
|
||||
return VERSION_PREFIX + str(self.version_guid)
|
||||
return u"{prefix}{guid}".format(prefix=VERSION_PREFIX, guid=self.version_guid)
|
||||
else:
|
||||
# raise InsufficientSpecificationError("missing package_id or version_guid")
|
||||
return '<InsufficientSpecificationError: missing package_id or version_guid>'
|
||||
@@ -213,7 +213,7 @@ class CourseLocator(Locator):
|
||||
"""
|
||||
Return a string containing the URL for this location.
|
||||
"""
|
||||
return 'edx://' + unicode(self)
|
||||
return u'edx://' + unicode(self)
|
||||
|
||||
def _validate_args(self, url, version_guid, package_id):
|
||||
"""
|
||||
@@ -526,7 +526,7 @@ class DefinitionLocator(Locator):
|
||||
Return a string containing the URL for this location.
|
||||
url(self) returns something like this: 'defx://version/519665f6223ebd6980884f2b'
|
||||
"""
|
||||
return 'defx://' + unicode(self)
|
||||
return u'defx://' + unicode(self)
|
||||
|
||||
def version(self):
|
||||
"""
|
||||
|
||||
@@ -7,7 +7,8 @@ BLOCK_PREFIX = r"block/"
|
||||
# Prefix for the version portion of a locator URL, when it is preceded by a course ID
|
||||
VERSION_PREFIX = r"version/"
|
||||
|
||||
ALLOWED_ID_CHARS = r'[a-zA-Z0-9_\-~.:]'
|
||||
ALLOWED_ID_CHARS = r'[\w\-~.:]'
|
||||
|
||||
|
||||
URL_RE_SOURCE = r"""
|
||||
(?P<tag>edx://)?
|
||||
@@ -20,7 +21,7 @@ URL_RE_SOURCE = r"""
|
||||
VERSION_PREFIX=VERSION_PREFIX, BLOCK_PREFIX=BLOCK_PREFIX
|
||||
)
|
||||
|
||||
URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE)
|
||||
URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE | re.UNICODE)
|
||||
|
||||
|
||||
def parse_url(string, tag_optional=False):
|
||||
@@ -54,7 +55,7 @@ def parse_url(string, tag_optional=False):
|
||||
return matched_dict
|
||||
|
||||
|
||||
BLOCK_RE = re.compile(r'^' + ALLOWED_ID_CHARS + r'+$', re.IGNORECASE)
|
||||
BLOCK_RE = re.compile(r'^' + ALLOWED_ID_CHARS + r'+$', re.IGNORECASE | re.UNICODE)
|
||||
|
||||
|
||||
def parse_block_ref(string):
|
||||
|
||||
@@ -73,13 +73,13 @@ def rewrite_nonportable_content_links(source_course_id, dest_course_id, text):
|
||||
# NOTE: ultimately link updating is not a hard requirement, so if something blows up with
|
||||
# the regex subsitution, log the error and continue
|
||||
try:
|
||||
c4x_link_base = '{0}/'.format(StaticContent.get_base_url_path_for_course_assets(course_location))
|
||||
c4x_link_base = u'{0}/'.format(StaticContent.get_base_url_path_for_course_assets(course_location))
|
||||
text = re.sub(_prefix_only_url_replace_regex(c4x_link_base), portable_asset_link_subtitution, text)
|
||||
except Exception, e:
|
||||
logging.warning("Error going regex subtituion %r on text = %r.\n\nError msg = %s", c4x_link_base, text, str(e))
|
||||
|
||||
try:
|
||||
jump_to_link_base = '/courses/{org}/{course}/{run}/jump_to/i4x://{org}/{course}/'.format(
|
||||
jump_to_link_base = u'/courses/{org}/{course}/{run}/jump_to/i4x://{org}/{course}/'.format(
|
||||
org=org, course=course, run=run
|
||||
)
|
||||
text = re.sub(_prefix_and_category_url_replace_regex(jump_to_link_base), portable_jump_to_link_substitution, text)
|
||||
@@ -94,7 +94,7 @@ def rewrite_nonportable_content_links(source_course_id, dest_course_id, text):
|
||||
#
|
||||
if source_course_id != dest_course_id:
|
||||
try:
|
||||
generic_courseware_link_base = '/courses/{org}/{course}/{run}/'.format(
|
||||
generic_courseware_link_base = u'/courses/{org}/{course}/{run}/'.format(
|
||||
org=org, course=course, run=run
|
||||
)
|
||||
text = re.sub(_prefix_only_url_replace_regex(generic_courseware_link_base), portable_asset_link_subtitution, text)
|
||||
|
||||
@@ -129,9 +129,9 @@ class ConditionalModuleBasicTest(unittest.TestCase):
|
||||
html = modules['cond_module'].render('student_view').content
|
||||
expected = modules['cond_module'].xmodule_runtime.render_template('conditional_ajax.html', {
|
||||
'ajax_url': modules['cond_module'].xmodule_runtime.ajax_url,
|
||||
'element_id': 'i4x-edX-conditional_test-conditional-SampleConditional',
|
||||
'id': 'i4x://edX/conditional_test/conditional/SampleConditional',
|
||||
'depends': 'i4x-edX-conditional_test-problem-SampleProblem',
|
||||
'element_id': u'i4x-edX-conditional_test-conditional-SampleConditional',
|
||||
'id': u'i4x://edX/conditional_test/conditional/SampleConditional',
|
||||
'depends': u'i4x-edX-conditional_test-problem-SampleProblem',
|
||||
})
|
||||
self.assertEquals(expected, html)
|
||||
|
||||
@@ -225,9 +225,9 @@ class ConditionalModuleXmlTest(unittest.TestCase):
|
||||
{
|
||||
# Test ajax url is just usage-id / handler_name
|
||||
'ajax_url': 'i4x://HarvardX/ER22x/conditional/condone/xmodule_handler',
|
||||
'element_id': 'i4x-HarvardX-ER22x-conditional-condone',
|
||||
'id': 'i4x://HarvardX/ER22x/conditional/condone',
|
||||
'depends': 'i4x-HarvardX-ER22x-problem-choiceprob'
|
||||
'element_id': u'i4x-HarvardX-ER22x-conditional-condone',
|
||||
'id': u'i4x://HarvardX/ER22x/conditional/condone',
|
||||
'depends': u'i4x-HarvardX-ER22x-problem-choiceprob'
|
||||
}
|
||||
)
|
||||
self.assertEqual(html, html_expect)
|
||||
|
||||
@@ -223,7 +223,7 @@ class XModuleMixin(XBlockMixin):
|
||||
try:
|
||||
child = self.runtime.get_block(child_loc)
|
||||
except ItemNotFoundError:
|
||||
log.exception('Unable to load item {loc}, skipping'.format(loc=child_loc))
|
||||
log.exception(u'Unable to load item {loc}, skipping'.format(loc=child_loc))
|
||||
continue
|
||||
self._child_instances.append(child)
|
||||
|
||||
@@ -538,7 +538,6 @@ class ResourceTemplates(object):
|
||||
template = yaml.safe_load(template_content)
|
||||
template['template_id'] = template_file
|
||||
templates.append(template)
|
||||
|
||||
return templates
|
||||
|
||||
@classmethod
|
||||
@@ -546,7 +545,7 @@ class ResourceTemplates(object):
|
||||
if getattr(cls, 'template_dir_name', None):
|
||||
dirname = os.path.join('templates', cls.template_dir_name)
|
||||
if not resource_isdir(__name__, dirname):
|
||||
log.warning("No resource directory {dir} found when loading {cls_name} templates".format(
|
||||
log.warning(u"No resource directory {dir} found when loading {cls_name} templates".format(
|
||||
dir=dirname,
|
||||
cls_name=cls.__name__,
|
||||
))
|
||||
|
||||
@@ -677,5 +677,5 @@ def _statsd_tag(course_title):
|
||||
"""
|
||||
Calculate the tag we will use for DataDog.
|
||||
"""
|
||||
tag = "course_email:{0}".format(course_title)
|
||||
tag = u"course_email:{0}".format(course_title)
|
||||
return tag[:200]
|
||||
|
||||
@@ -343,7 +343,7 @@ def _dispatch(table, action, user, obj):
|
||||
action)
|
||||
return result
|
||||
|
||||
raise ValueError("Unknown action for object type '{0}': '{1}'".format(
|
||||
raise ValueError(u"Unknown action for object type '{0}': '{1}'".format(
|
||||
type(obj), action))
|
||||
|
||||
|
||||
|
||||
@@ -321,10 +321,10 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
org, course_num, run = course_id.split("/")
|
||||
|
||||
tags = [
|
||||
"org:{0}".format(org),
|
||||
"course:{0}".format(course_num),
|
||||
"run:{0}".format(run),
|
||||
"score_bucket:{0}".format(score_bucket)
|
||||
u"org:{0}".format(org),
|
||||
u"course:{0}".format(course_num),
|
||||
u"run:{0}".format(run),
|
||||
u"score_bucket:{0}".format(score_bucket)
|
||||
]
|
||||
|
||||
if grade_bucket_type is not None:
|
||||
@@ -443,7 +443,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
make_psychometrics_data_update_handler(course_id, user, descriptor.location.url())
|
||||
)
|
||||
|
||||
system.set('user_is_staff', has_access(user, descriptor.location, 'staff', course_id))
|
||||
system.set(u'user_is_staff', has_access(user, descriptor.location, u'staff', course_id))
|
||||
|
||||
# make an ErrorDescriptor -- assuming that the descriptor's system is ok
|
||||
if has_access(user, descriptor.location, 'staff', course_id):
|
||||
|
||||
@@ -238,7 +238,7 @@ def index(request, course_id, chapter=None, section=None,
|
||||
registered = registered_for_course(course, user)
|
||||
if not registered:
|
||||
# TODO (vshnayder): do course instructors need to be registered to see course?
|
||||
log.debug('User %s tried to view course %s but is not enrolled' % (user, course.location.url()))
|
||||
log.debug(u'User {0} tried to view course {1} but is not enrolled'.format(user, course.location.url()))
|
||||
return redirect(reverse('about_course', args=[course.id]))
|
||||
|
||||
masq = setup_masquerade(request, staff_access)
|
||||
@@ -249,8 +249,8 @@ def index(request, course_id, chapter=None, section=None,
|
||||
|
||||
course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id)
|
||||
if course_module is None:
|
||||
log.warning('If you see this, something went wrong: if we got this'
|
||||
' far, should have gotten a course module for this user')
|
||||
log.warning(u'If you see this, something went wrong: if we got this'
|
||||
u' far, should have gotten a course module for this user')
|
||||
return redirect(reverse('about_course', args=[course.id]))
|
||||
|
||||
if chapter is None:
|
||||
@@ -424,9 +424,9 @@ def jump_to(request, course_id, location):
|
||||
try:
|
||||
(course_id, chapter, section, position) = path_to_location(modulestore(), course_id, location)
|
||||
except ItemNotFoundError:
|
||||
raise Http404("No data at this location: {0}".format(location))
|
||||
raise Http404(u"No data at this location: {0}".format(location))
|
||||
except NoPathToItem:
|
||||
raise Http404("This location is not in any class: {0}".format(location))
|
||||
raise Http404(u"This location is not in any class: {0}".format(location))
|
||||
|
||||
# choose the appropriate view (and provide the necessary args) based on the
|
||||
# args provided by the redirect.
|
||||
|
||||
@@ -15,7 +15,8 @@ def cached_has_permission(user, permission, course_id=None):
|
||||
Call has_permission if it's not cached. A change in a user's role or
|
||||
a role's permissions will only become effective after CACHE_LIFESPAN seconds.
|
||||
"""
|
||||
key = "permission_%d_%s_%s" % (user.id, str(course_id), permission)
|
||||
key = u"permission_{user_id:d}_{course_id}_{permission}".format(
|
||||
user_id=user.id, course_id=course_id, permission=permission)
|
||||
val = CACHE.get(key, None)
|
||||
if val not in [True, False]:
|
||||
val = has_permission(user, permission, course_id=course_id)
|
||||
|
||||
@@ -173,7 +173,7 @@ def instructor_dashboard(request, course_id):
|
||||
|
||||
# complete the url using information about the current course:
|
||||
(org, course_name, _) = course_id.split("/")
|
||||
return "i4x://" + org + "/" + course_name + "/" + urlname
|
||||
return u"i4x://{org}/{name}/{url}".format(org=org, name=course_name, url=urlname)
|
||||
|
||||
def get_student_from_identifier(unique_student_identifier):
|
||||
"""Gets a student object using either an email address or username"""
|
||||
@@ -782,7 +782,7 @@ def instructor_dashboard(request, course_id):
|
||||
logs and swallows errors.
|
||||
"""
|
||||
url = settings.ANALYTICS_SERVER_URL + \
|
||||
"get?aname={}&course_id={}&apikey={}".format(analytics_name,
|
||||
u"get?aname={}&course_id={}&apikey={}".format(analytics_name,
|
||||
course_id,
|
||||
settings.ANALYTICS_API_KEY)
|
||||
try:
|
||||
|
||||
@@ -66,7 +66,7 @@ def staff_grading_notifications(course, user):
|
||||
def peer_grading_notifications(course, user):
|
||||
system = LmsModuleSystem(
|
||||
track_function=None,
|
||||
get_module = None,
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
)
|
||||
@@ -115,7 +115,7 @@ def combined_notifications(course, user):
|
||||
#Set up return values so that we can return them for error cases
|
||||
pending_grading = False
|
||||
img_path = ""
|
||||
notifications={}
|
||||
notifications = {}
|
||||
notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}
|
||||
|
||||
#We don't want to show anonymous users anything.
|
||||
@@ -126,7 +126,7 @@ def combined_notifications(course, user):
|
||||
system = LmsModuleSystem(
|
||||
static_url="/static",
|
||||
track_function=None,
|
||||
get_module = None,
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
)
|
||||
@@ -159,7 +159,7 @@ def combined_notifications(course, user):
|
||||
#Non catastrophic error, so no real action
|
||||
#This is a dev_facing_error
|
||||
log.exception(
|
||||
"Problem with getting notifications from controller query service for course {0} user {1}.".format(
|
||||
u"Problem with getting notifications from controller query service for course {0} user {1}.".format(
|
||||
course_id, student_id))
|
||||
|
||||
if pending_grading:
|
||||
@@ -185,7 +185,7 @@ def set_value_in_cache(student_id, course_id, notification_type, value):
|
||||
|
||||
|
||||
def create_key_name(student_id, course_id, notification_type):
|
||||
key_name = "{prefix}{type}_{course}_{student}".format(prefix=KEY_PREFIX, type=notification_type, course=course_id,
|
||||
key_name = u"{prefix}{type}_{course}_{student}".format(prefix=KEY_PREFIX, type=notification_type, course=course_id,
|
||||
student=student_id)
|
||||
return key_name
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ class MockStaffGradingService(object):
|
||||
'min_for_ml': 10})
|
||||
]})
|
||||
|
||||
|
||||
def save_grade(self, course_id, grader_id, submission_id, score, feedback, skipped, rubric_scores,
|
||||
submission_flagged):
|
||||
return self.get_next(course_id, 'fake location', grader_id)
|
||||
@@ -81,7 +80,7 @@ class StaffGradingService(GradingService):
|
||||
config['system'] = LmsModuleSystem(
|
||||
static_url='/static',
|
||||
track_function=None,
|
||||
get_module = None,
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
)
|
||||
@@ -93,7 +92,6 @@ class StaffGradingService(GradingService):
|
||||
self.get_problem_list_url = self.url + '/get_problem_list/'
|
||||
self.get_notifications_url = self.url + "/get_notifications/"
|
||||
|
||||
|
||||
def get_problem_list(self, course_id, grader_id):
|
||||
"""
|
||||
Get the list of problems for a given course.
|
||||
@@ -113,7 +111,6 @@ class StaffGradingService(GradingService):
|
||||
params = {'course_id': course_id, 'grader_id': grader_id}
|
||||
return self.get(self.get_problem_list_url, params)
|
||||
|
||||
|
||||
def get_next(self, course_id, location, grader_id):
|
||||
"""
|
||||
Get the next thing to grade.
|
||||
@@ -137,7 +134,6 @@ class StaffGradingService(GradingService):
|
||||
'grader_id': grader_id})
|
||||
return json.dumps(self._render_rubric(response))
|
||||
|
||||
|
||||
def save_grade(self, course_id, grader_id, submission_id, score, feedback, skipped, rubric_scores,
|
||||
submission_flagged):
|
||||
"""
|
||||
|
||||
@@ -35,7 +35,7 @@ def quote_slashes(text):
|
||||
';;'. By making the escape sequence fixed length, and escaping
|
||||
identifier character ';', we are able to reverse the escaping.
|
||||
"""
|
||||
return re.sub(r'[;/]', _quote_slashes, text)
|
||||
return re.sub(ur'[;/]', _quote_slashes, text)
|
||||
|
||||
|
||||
def _unquote_slashes(match):
|
||||
@@ -84,7 +84,7 @@ def handler_url(course_id, block, handler, suffix='', query='', thirdparty=False
|
||||
|
||||
url = reverse(view_name, kwargs={
|
||||
'course_id': course_id,
|
||||
'usage_id': quote_slashes(str(block.scope_ids.usage_id)),
|
||||
'usage_id': quote_slashes(unicode(block.scope_ids.usage_id).encode('utf-8')),
|
||||
'handler': handler,
|
||||
'suffix': suffix,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user