Commit 0a79130b by Calen Pennington

Make problem previews work by saving problem state in the current request session

parent 408726e6
from util.json_request import expect_json
import json
import logging
from collections import defaultdict
from django.http import HttpResponse, Http404
from django.contrib.auth.decorators import login_required
......@@ -15,6 +17,10 @@ from static_replace import replace_urls
from mitxmako.shortcuts import render_to_response, render_to_string
from xmodule.modulestore.django import modulestore
from xmodule_modifiers import replace_static_urls, wrap_xmodule
from xmodule.exceptions import NotFoundError
from functools import partial
log = logging.getLogger(__name__)
# ==== Public views ==================================================
......@@ -103,7 +109,7 @@ def edit_item(request):
'js_module': item.js_module_name,
'category': item.category,
'name': item.name,
'previews': get_module_previews(item),
'previews': get_module_previews(request, item),
})
......@@ -124,16 +130,64 @@ def user_author_string(user):
@login_required
def preview_dispatch(request, module_id, dispatch):
def preview_dispatch(request, preview_id, location, dispatch=None):
"""
Dispatch an AJAX action to a preview XModule
Expects a POST request, and passes the arguments to the module
module_id: The Location of the module to dispatch to
preview_id (str): An identifier specifying which preview this module is used for
location: The Location of the module to dispatch to
dispatch: The action to execute
"""
pass
instance_state, shared_state = load_preview_state(request, preview_id, location)
descriptor = modulestore().get_item(location)
instance = load_preview_module(request, preview_id, descriptor, instance_state, shared_state)
# Let the module handle the AJAX
try:
ajax_return = instance.handle_ajax(dispatch, request.POST)
except NotFoundError:
log.exception("Module indicating to user that request doesn't exist")
raise Http404
except:
log.exception("error processing ajax call")
raise
save_preview_state(request, preview_id, location, instance.get_instance_state(), instance.get_shared_state())
return HttpResponse(ajax_return)
def load_preview_state(request, preview_id, location):
"""
Load the state of a preview module from the request
preview_id (str): An identifier specifying which preview this module is used for
location: The Location of the module to dispatch to
"""
if 'preview_states' not in request.session:
request.session['preview_states'] = defaultdict(dict)
instance_state = request.session['preview_states'][preview_id, location].get('instance')
shared_state = request.session['preview_states'][preview_id, location].get('shared')
return instance_state, shared_state
def save_preview_state(request, preview_id, location, instance_state, shared_state):
"""
Load the state of a preview module to the request
preview_id (str): An identifier specifying which preview this module is used for
location: The Location of the module to dispatch to
instance_state: The instance state to save
shared_state: The shared state to save
"""
if 'preview_states' not in request.session:
request.session['preview_states'] = defaultdict(dict)
request.session['preview_states'][preview_id, location]['instance'] = instance_state
request.session['preview_states'][preview_id, location]['shared'] = shared_state
def render_from_lms(template_name, dictionary, context=None, namespace='main'):
......@@ -143,54 +197,64 @@ def render_from_lms(template_name, dictionary, context=None, namespace='main'):
return render_to_string(template_name, dictionary, context, namespace="lms." + namespace)
def sample_module_system(descriptor):
def preview_module_system(request, preview_id, descriptor):
"""
Returns a ModuleSystem for the specified descriptor that is specialized for
rendering module previews.
request: The active django request
preview_id (str): An identifier specifying which preview this module is used for
descriptor: An XModuleDescriptor
"""
return ModuleSystem(
ajax_url=reverse('preview_dispatch', args=[descriptor.location.url(), '']),
ajax_url=reverse('preview_dispatch', args=[preview_id, descriptor.location.url(), '']),
# TODO (cpennington): Do we want to track how instructors are using the preview problems?
track_function=lambda x: None,
track_function=lambda type, event: None,
filestore=descriptor.system.resources_fs,
get_module=get_sample_module,
get_module=partial(get_preview_module, request, preview_id),
render_template=render_from_lms,
debug=True,
replace_urls=replace_urls
)
def get_sample_module(location):
def get_preview_module(request, preview_id, location):
"""
Returns a sample XModule at the specified location. The sample_data is chosen arbitrarily
from the set of sample data for the descriptor specified by Location
Returns a preview XModule at the specified location. The preview_data is chosen arbitrarily
from the set of preview data for the descriptor specified by Location
request: The active django request
preview_id (str): An identifier specifying which preview this module is used for
location: A Location
"""
descriptor = modulestore().get_item(location)
instance_state, shared_state = descriptor.get_sample_state()[0]
return load_sample_module(descriptor, instance_state, shared_state)
return load_preview_module(request, preview_id, descriptor, instance_state, shared_state)
def load_sample_module(descriptor, instance_state, shared_state):
def load_preview_module(request, preview_id, descriptor, instance_state, shared_state):
"""
Return a sample XModule instantiated from the supplied descriptor, instance_state, and shared_state
Return a preview XModule instantiated from the supplied descriptor, instance_state, and shared_state
request: The active django request
preview_id (str): An identifier specifying which preview this module is used for
descriptor: An XModuleDescriptor
instance_state: An instance state string
shared_state: A shared state string
"""
system = sample_module_system(descriptor)
system = preview_module_system(request, preview_id, descriptor)
module = descriptor.xmodule_constructor(system)(instance_state, shared_state)
module.get_html = replace_static_urls(
wrap_xmodule(module.get_html, module, "xmodule_display.html"),
module.metadata['data_dir']
)
save_preview_state(request, preview_id, descriptor.location.url(),
module.get_instance_state(), module.get_shared_state())
return module
def get_module_previews(descriptor):
def get_module_previews(request, descriptor):
"""
Returns a list of preview XModule html contents. One preview is returned for each
pair of states returned by get_sample_state() for the supplied descriptor.
......@@ -198,8 +262,8 @@ def get_module_previews(descriptor):
descriptor: An XModuleDescriptor
"""
preview_html = []
for instance_state, shared_state in descriptor.get_sample_state():
module = load_sample_module(descriptor, instance_state, shared_state)
for idx, (instance_state, shared_state) in enumerate(descriptor.get_sample_state()):
module = load_preview_module(request, str(idx), descriptor, instance_state, shared_state)
preview_html.append(module.get_html())
return preview_html
......@@ -225,6 +289,6 @@ def save_item(request):
export_to_github(course, "CMS Edit", author_string)
descriptor = modulestore().get_item(item_location)
preview_html = get_module_previews(descriptor)
preview_html = get_module_previews(request, descriptor)
return HttpResponse(json.dumps(preview_html))
......@@ -14,7 +14,8 @@ urlpatterns = ('',
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<name>[^/]+)$',
'contentstore.views.course_index', name='course_index'),
url(r'^github_service_hook$', 'github_sync.views.github_post_receive'),
url(r'^preview/modx/(?P<location>.*?)/(?P<dispatch>[^/]*)$', 'contentstore.views.preview_dispatch', name='preview_dispatch')
url(r'^preview/modx/(?P<preview_id>[^/]*)/(?P<location>.*?)/(?P<dispatch>[^/]*)$',
'contentstore.views.preview_dispatch', name='preview_dispatch')
)
# User creation and updating views
......
......@@ -21,9 +21,3 @@
% for chapter in toc:
${make_chapter(chapter)}
% endfor
## add a link to allow course.xml to be reloaded from the git content repo
##% if settings.QUICKEDIT:
## <h3><a href="#">quickedit</a></h3>
## <ul><li><a href="${MITX_ROOT_URL}/quickedit/course.xml">gitreload</a></li></ul>
##% endif
......@@ -4,12 +4,6 @@
% if problem['weight'] != 1:
: ${ problem['weight'] } points
% endif
% if settings.QUICKEDIT:
<section class="staff">
<a href=${MITX_ROOT_URL}/quickedit/${id}>Quick Edit Problem</a>
</section>
% endif
</h2>
<section class="problem">
......
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