115 lines
3.9 KiB
Python
115 lines
3.9 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):
|
|
"""
|
|
Match static urls in quotes that don't end in '?raw'.
|
|
|
|
To anyone contemplating making this more complicated:
|
|
http://xkcd.com/1171/
|
|
"""
|
|
return r"""
|
|
(?x) # flags=re.VERBOSE
|
|
(?P<quote>\\?['"]) # the opening quotes
|
|
(?P<prefix>{prefix}) # the prefix
|
|
(?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):
|
|
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):
|
|
original = match.group(0)
|
|
prefix = match.group('prefix')
|
|
quote = match.group('quote')
|
|
rest = match.group('rest')
|
|
|
|
# Don't mess with things that end in '?raw'
|
|
if rest.endswith('?raw'):
|
|
return original
|
|
|
|
# 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)
|
|
# In debug mode, if we can find the url as is,
|
|
elif settings.DEBUG and finders.find(rest, True):
|
|
return original
|
|
# Otherwise, look the file up in staticfiles_storage, and append the data directory if needed
|
|
else:
|
|
course_path = "/".join((data_directory, rest))
|
|
|
|
try:
|
|
if staticfiles_storage.exists(rest):
|
|
url = staticfiles_storage.url(rest)
|
|
else:
|
|
url = staticfiles_storage.url(course_path)
|
|
# And if that fails, assume that it's course content, and add manually data directory
|
|
except Exception as err:
|
|
log.warning("staticfiles_storage couldn't find path {0}: {1}".format(
|
|
rest, str(err)))
|
|
url = "".join([prefix, course_path])
|
|
|
|
return "".join([quote, url, quote])
|
|
|
|
return re.sub(
|
|
_url_replace_regex('/static/(?!{data_dir})'.format(data_dir=data_directory)),
|
|
replace_static_url,
|
|
text
|
|
)
|