104 lines
3.7 KiB
Python
104 lines
3.7 KiB
Python
import logging
|
|
import re
|
|
|
|
from staticfiles.storage import staticfiles_storage
|
|
from staticfiles import finders
|
|
from django.conf import settings
|
|
|
|
from xmodule.modulestore.django import modulestore
|
|
from xmodule.modulestore.xml import XMLModuleStore
|
|
from xmodule.contentstore.content import StaticContent
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def _url_replace_regex(prefix):
|
|
return r"""
|
|
(?x) # flags=re.VERBOSE
|
|
(?P<quote>\\?['"]) # the opening quotes
|
|
(?P<prefix>{prefix}) # theeprefix
|
|
(?P<rest>.*?) # everything else in the url
|
|
(?P=quote) # the first matching closing quote
|
|
""".format(prefix=prefix)
|
|
|
|
def try_staticfiles_lookup(path):
|
|
"""
|
|
Try to lookup a path in staticfiles_storage. If it fails, return
|
|
a dead link instead of raising an exception.
|
|
"""
|
|
try:
|
|
url = staticfiles_storage.url(path)
|
|
except Exception as err:
|
|
log.warning("staticfiles_storage couldn't find path {0}: {1}".format(
|
|
path, str(err)))
|
|
# Just return the original path; don't kill everything.
|
|
url = path
|
|
return url
|
|
|
|
|
|
def replace_course_urls(text, course_id):
|
|
"""
|
|
Replace /course/$stuff urls with /courses/$course_id/$stuff urls
|
|
|
|
text: The text to replace
|
|
course_module: A CourseDescriptor
|
|
|
|
returns: text with the links replaced
|
|
"""
|
|
|
|
|
|
def replace_course_url(match):
|
|
log.warning("Course match: %s", match.groupdict())
|
|
quote = match.group('quote')
|
|
rest = match.group('rest')
|
|
return "".join([quote, '/courses/' + course_id + '/', rest, quote])
|
|
|
|
return re.sub(_url_replace_regex('/course/'), replace_course_url, text)
|
|
|
|
|
|
def replace_static_urls(text, data_directory, course_namespace=None):
|
|
"""
|
|
Replace /static/$stuff urls either with their correct url as generated by collectstatic,
|
|
(/static/$md5_hashed_stuff) or by the course-specific content static url
|
|
/static/$course_data_dir/$stuff, or, if course_namespace is not None, by the
|
|
correct url in the contentstore (c4x://)
|
|
|
|
text: The source text to do the substitution in
|
|
data_directory: The directory in which course data is stored
|
|
course_namespace: The course identifier used to distinguish static content for this course in studio
|
|
"""
|
|
|
|
def replace_static_url(match):
|
|
log.warning(match.groupdict())
|
|
quote = match.group('quote')
|
|
rest = match.group('rest')
|
|
|
|
# course_namespace is not None, then use studio style urls
|
|
if course_namespace is not None and not isinstance(modulestore(), XMLModuleStore):
|
|
url = StaticContent.convert_legacy_static_url(rest, course_namespace)
|
|
log.warning("From modulestore: %s", url)
|
|
# If we're in debug mode, and the file as requested exists, then don't change the links
|
|
elif (settings.DEBUG and finders.find(rest, True)):
|
|
url = match.group('prefix') + rest
|
|
log.warning("From finder: %s", url)
|
|
# Otherwise, look the file up in staticfiles_storage
|
|
else:
|
|
path = data_directory + '/' + rest
|
|
try:
|
|
url = staticfiles_storage.url(path)
|
|
log.warning("From staticfiles_storage: %s", url)
|
|
# And if that fails, return the path unmodified
|
|
except Exception as err:
|
|
log.warning("staticfiles_storage couldn't find path {0}: {1}".format(
|
|
path, str(err)))
|
|
url = path
|
|
log.warning("Fallback: %s", url)
|
|
log.warning("".join([quote, url, quote]))
|
|
return "".join([quote, url, quote])
|
|
|
|
return re.sub(
|
|
_url_replace_regex('/static/(?!{data_dir})'.format(data_dir=data_directory)),
|
|
replace_static_url,
|
|
text
|
|
)
|