Commit 5406b9bb by Calen Pennington

Make /static/ urls work in the courseware

parent dbfcd78c
from staticfiles.storage import staticfiles_storage from staticfiles.storage import staticfiles_storage
import re import re
PREFIX = '/static/'
STATIC_PATTERN = re.compile(r"""
(?P<quote>['"]) # the opening quotes
{prefix} # the prefix
(?P<rest>.*?) # everything else in the url
(?P=quote) # the first matching closing quote
""".format(prefix=PREFIX), re.VERBOSE)
PREFIX_LEN = len(PREFIX)
def replace(static_url): def replace(static_url, prefix=None):
if prefix is None:
prefix = ''
else:
prefix = prefix + '/'
quote = static_url.group('quote') quote = static_url.group('quote')
url = staticfiles_storage.url(static_url.group('rest')) url = staticfiles_storage.url(prefix + static_url.group('rest'))
return "".join([quote, url, quote]) return "".join([quote, url, quote])
def replace_urls(text):
return STATIC_PATTERN.sub(replace, text) def replace_urls(text, staticfiles_prefix=None, replace_prefix='/static/'):
def replace_url(static_url):
return replace(static_url, staticfiles_prefix)
return re.sub(r"""
(?P<quote>\\?['"]) # the opening quotes
{prefix} # the prefix
(?P<rest>.*?) # everything else in the url
(?P=quote) # the first matching closing quote
""".format(prefix=replace_prefix), replace_url, text, flags=re.VERBOSE)
...@@ -15,6 +15,7 @@ from xmodule.raw_module import RawDescriptor ...@@ -15,6 +15,7 @@ from xmodule.raw_module import RawDescriptor
from progress import Progress from progress import Progress
from capa.capa_problem import LoncapaProblem from capa.capa_problem import LoncapaProblem
from capa.responsetypes import StudentInputError from capa.responsetypes import StudentInputError
from static_replace import replace_urls
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -258,7 +259,7 @@ class CapaModule(XModule): ...@@ -258,7 +259,7 @@ class CapaModule(XModule):
html = '<div id="problem_{id}" class="problem" data-url="{ajax_url}">'.format( html = '<div id="problem_{id}" class="problem" data-url="{ajax_url}">'.format(
id=self.location.html_id(), ajax_url=self.system.ajax_url) + html + "</div>" id=self.location.html_id(), ajax_url=self.system.ajax_url) + html + "</div>"
return html return replace_urls(html, self.metadata['data_dir'])
def handle_ajax(self, dispatch, get): def handle_ajax(self, dispatch, get):
''' '''
......
...@@ -115,7 +115,9 @@ class XMLModuleStore(ModuleStore): ...@@ -115,7 +115,9 @@ class XMLModuleStore(ModuleStore):
MakoDescriptorSystem.__init__(self, **system_kwargs) MakoDescriptorSystem.__init__(self, **system_kwargs)
XMLParsingSystem.__init__(self, **system_kwargs) XMLParsingSystem.__init__(self, **system_kwargs)
return ImportSystem(self).process_xml(etree.tostring(course_data)) course_descriptor = ImportSystem(self).process_xml(etree.tostring(course_data))
course_descriptor.metadata['data_dir'] = course_dir
return course_descriptor
def get_item(self, location): def get_item(self, location):
""" """
......
...@@ -211,7 +211,13 @@ class XModuleDescriptor(Plugin): ...@@ -211,7 +211,13 @@ class XModuleDescriptor(Plugin):
js_module = None js_module = None
# A list of metadata that this module can inherit from its parent module # A list of metadata that this module can inherit from its parent module
inheritable_metadata = ('graded', 'due', 'graceperiod', 'showanswer', 'rerandomize') inheritable_metadata = (
'graded', 'due', 'graceperiod', 'showanswer', 'rerandomize',
# This is used by the XMLModuleStore to provide for locations for static files,
# and will need to be removed when that code is removed
'data_dir'
)
# A list of descriptor attributes that must be equal for the discriptors to be # A list of descriptor attributes that must be equal for the discriptors to be
# equal # equal
......
import json import json
import logging import logging
import os
from django.conf import settings from django.conf import settings
from django.http import Http404 from django.http import Http404
from django.http import HttpResponse from django.http import HttpResponse
from lxml import etree from functools import wraps
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from mitxmako.shortcuts import render_to_string from mitxmako.shortcuts import render_to_string
from models import StudentModule, StudentModuleCache from models import StudentModule, StudentModuleCache
from static_replace import replace_urls
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -222,6 +222,12 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -222,6 +222,12 @@ def get_module(user, request, location, student_module_cache, position=None):
module = descriptor.xmodule_constructor(system)(instance_state, shared_state) module = descriptor.xmodule_constructor(system)(instance_state, shared_state)
# TODO (cpennington): When modules are shared between courses, the static
# prefix is going to have to be specific to the module, not the directory
# that the xml was loaded from
prefix = module.metadata['data_dir']
module = replace_static_urls(module, prefix)
if settings.MITX_FEATURES.get('DISPLAY_HISTOGRAMS_TO_STAFF') and user.is_staff: if settings.MITX_FEATURES.get('DISPLAY_HISTOGRAMS_TO_STAFF') and user.is_staff:
module = add_histogram(module) module = add_histogram(module)
...@@ -251,9 +257,32 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -251,9 +257,32 @@ def get_module(user, request, location, student_module_cache, position=None):
return (module, instance_module, shared_module, descriptor.category) return (module, instance_module, shared_module, descriptor.category)
def replace_static_urls(module, prefix):
"""
Updates the supplied module with a new get_html function that wraps
the old get_html function and substitutes urls of the form /static/...
with urls that are /static/<prefix>/...
"""
original_get_html = module.get_html
@wraps(original_get_html)
def get_html():
return replace_urls(original_get_html(), staticfiles_prefix=prefix)
module.get_html = get_html
return module
def add_histogram(module): def add_histogram(module):
"""
Updates the supplied module with a new get_html function that wraps
the output of the old get_html function with additional information
for admin users only, including a histogram of student answers and the
definition of the xmodule
"""
original_get_html = module.get_html original_get_html = module.get_html
@wraps(original_get_html)
def get_html(): def get_html():
module_id = module.id module_id = module.id
histogram = grade_histogram(module_id) histogram = grade_histogram(module_id)
......
...@@ -19,6 +19,7 @@ Longer TODO: ...@@ -19,6 +19,7 @@ Longer TODO:
multiple sites, but we do need a way to map their data assets. multiple sites, but we do need a way to map their data assets.
""" """
import sys import sys
import os
import tempfile import tempfile
import glob2 import glob2
...@@ -167,19 +168,17 @@ MANAGERS = ADMINS ...@@ -167,19 +168,17 @@ MANAGERS = ADMINS
# Static content # Static content
STATIC_URL = '/static/' STATIC_URL = '/static/'
ADMIN_MEDIA_PREFIX = '/static/admin/' ADMIN_MEDIA_PREFIX = '/static/admin/'
STATIC_ROOT = ENV_ROOT / "staticfiles" STATIC_ROOT = ENV_ROOT / "staticfiles"
# FIXME: We should iterate through the courses we have, adding the static
# contents for each of them. (Right now we just use symlinks.)
STATICFILES_DIRS = [ STATICFILES_DIRS = [
PROJECT_ROOT / "static", PROJECT_ROOT / "static",
ASKBOT_ROOT / "askbot" / "skins", ASKBOT_ROOT / "askbot" / "skins",
("circuits", DATA_DIR / "images"),
("handouts", DATA_DIR / "handouts"),
("subs", DATA_DIR / "subs"),
# This is how you would use the textbook images locally ] + [
# ("book", ENV_ROOT / "book_images") # TODO (cpennington): When courses are stored in a database, this
# should no longer be added to STATICFILES
(course_dir, DATA_DIR / course_dir)
for course_dir in os.listdir(DATA_DIR)
] ]
# Locale/Internationalization # Locale/Internationalization
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
<script type="text/javascript" src="${static.url('js/vendor/jquery.cookie.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/jquery.cookie.js')}"></script>
<script type="text/javascript" src="${static.url('js/vendor/jquery.qtip.min.js')}"></script> <script type="text/javascript" src="${static.url('js/vendor/jquery.qtip.min.js')}"></script>
## TODO (cpennington): Remove this when we have a good way for modules to specify js to load on the page
## and in the wiki
<script type="text/javascript" src="${static.url('js/schematic.js')}"></script>
% if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']: % if settings.MITX_FEATURES['USE_DJANGO_PIPELINE']:
<%static:js group='application'/> <%static:js group='application'/>
% endif % endif
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
</h2> </h2>
<section class="problem"> <section class="problem">
${ static.replace_urls(problem['html']) } ${ problem['html'] }
<section class="action"> <section class="action">
<input type="hidden" name="problem_id" value="${ problem['name'] }"> <input type="hidden" name="problem_id" value="${ problem['name'] }">
......
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