138 lines
3.9 KiB
Python
138 lines
3.9 KiB
Python
"""
|
|
Module implementing `xblock.runtime.Runtime` functionality for the LMS
|
|
"""
|
|
|
|
import re
|
|
|
|
from django.core.urlresolvers import reverse
|
|
|
|
from xmodule.x_module import ModuleSystem
|
|
|
|
|
|
def _quote_slashes(match):
|
|
"""
|
|
Helper function for `quote_slashes`
|
|
"""
|
|
matched = match.group(0)
|
|
# We have to escape ';', because that is our
|
|
# escape sequence identifier (otherwise, the escaping)
|
|
# couldn't distinguish between us adding ';_' to the string
|
|
# and ';_' appearing naturally in the string
|
|
if matched == ';':
|
|
return ';;'
|
|
elif matched == '/':
|
|
return ';_'
|
|
else:
|
|
return matched
|
|
|
|
|
|
def quote_slashes(text):
|
|
"""
|
|
Quote '/' characters so that they aren't visible to
|
|
django's url quoting, unquoting, or url regex matching.
|
|
|
|
Escapes '/'' to the sequence ';_', and ';' to the sequence
|
|
';;'. 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)
|
|
|
|
|
|
def _unquote_slashes(match):
|
|
"""
|
|
Helper function for `unquote_slashes`
|
|
"""
|
|
matched = match.group(0)
|
|
if matched == ';;':
|
|
return ';'
|
|
elif matched == ';_':
|
|
return '/'
|
|
else:
|
|
return matched
|
|
|
|
|
|
def unquote_slashes(text):
|
|
"""
|
|
Unquote slashes quoted by `quote_slashes`
|
|
"""
|
|
return re.sub(r'(;;|;_)', _unquote_slashes, text)
|
|
|
|
|
|
def handler_url(course_id, block, handler, suffix='', query='', thirdparty=False):
|
|
"""
|
|
Return an XBlock handler url for the specified course, block and handler.
|
|
|
|
If handler is an empty string, this function is being used to create a
|
|
prefix of the general URL, which is assumed to be followed by handler name
|
|
and suffix.
|
|
|
|
If handler is specified, then it is checked for being a valid handler
|
|
function, and ValueError is raised if not.
|
|
|
|
"""
|
|
view_name = 'xblock_handler'
|
|
if handler:
|
|
# Be sure this is really a handler.
|
|
func = getattr(block, handler, None)
|
|
if not func:
|
|
raise ValueError("{!r} is not a function name".format(handler))
|
|
if not getattr(func, "_is_xblock_handler", False):
|
|
raise ValueError("{!r} is not a handler name".format(handler))
|
|
|
|
if thirdparty:
|
|
view_name = 'xblock_handler_noauth'
|
|
|
|
url = reverse(view_name, kwargs={
|
|
'course_id': course_id,
|
|
'usage_id': quote_slashes(str(block.scope_ids.usage_id)),
|
|
'handler': handler,
|
|
'suffix': suffix,
|
|
})
|
|
|
|
# If suffix is an empty string, remove the trailing '/'
|
|
if not suffix:
|
|
url = url.rstrip('/')
|
|
|
|
# If there is a query string, append it
|
|
if query:
|
|
url += '?' + query
|
|
|
|
return url
|
|
|
|
|
|
def handler_prefix(course_id, block):
|
|
"""
|
|
Returns a prefix for use by the Javascript handler_url function.
|
|
|
|
The prefix is a valid handler url after the handler name is slash-appended
|
|
to it.
|
|
"""
|
|
# This depends on handler url having the handler_name as the final piece of the url
|
|
# so that leaving an empty handler_name really does leave the opportunity to append
|
|
# the handler_name on the frontend
|
|
|
|
# This is relied on by the xblock/runtime.v1.coffee frontend handlerUrl function
|
|
return handler_url(course_id, block, '').rstrip('/?')
|
|
|
|
|
|
class LmsHandlerUrls(object):
|
|
"""
|
|
A runtime mixin that provides a handler_url function that routes
|
|
to the LMS' xblock handler view.
|
|
|
|
This must be mixed in to a runtime that already accepts and stores
|
|
a course_id
|
|
"""
|
|
# pylint: disable=unused-argument
|
|
# pylint: disable=no-member
|
|
def handler_url(self, block, handler_name, suffix='', query='', thirdparty=False):
|
|
"""See :method:`xblock.runtime:Runtime.handler_url`"""
|
|
return handler_url(self.course_id, block, handler_name, suffix='', query='', thirdparty=thirdparty)
|
|
|
|
|
|
class LmsModuleSystem(LmsHandlerUrls, ModuleSystem): # pylint: disable=abstract-method
|
|
"""
|
|
ModuleSystem specialized to the LMS
|
|
"""
|
|
pass
|