From 0a79130b1174cdf6827b2ff09f1d1319d68c65d2 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Fri, 20 Jul 2012 13:29:18 -0400 Subject: [PATCH] Make problem previews work by saving problem state in the current request session --- cms/djangoapps/contentstore/views.py | 102 ++++++++++++++++++++++----- cms/urls.py | 3 +- lms/templates/accordion.html | 6 -- lms/templates/problem.html | 6 -- 4 files changed, 85 insertions(+), 32 deletions(-) diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index e1722c0d65..6d5b2117c4 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -1,5 +1,7 @@ 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)) diff --git a/cms/urls.py b/cms/urls.py index 066a2d9941..15aa11ba8f 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -14,7 +14,8 @@ urlpatterns = ('', url(r'^(?P[^/]+)/(?P[^/]+)/course/(?P[^/]+)$', 'contentstore.views.course_index', name='course_index'), url(r'^github_service_hook$', 'github_sync.views.github_post_receive'), - url(r'^preview/modx/(?P.*?)/(?P[^/]*)$', 'contentstore.views.preview_dispatch', name='preview_dispatch') + url(r'^preview/modx/(?P[^/]*)/(?P.*?)/(?P[^/]*)$', + 'contentstore.views.preview_dispatch', name='preview_dispatch') ) # User creation and updating views diff --git a/lms/templates/accordion.html b/lms/templates/accordion.html index 974d7da451..d9e6cee61e 100644 --- a/lms/templates/accordion.html +++ b/lms/templates/accordion.html @@ -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: -##

quickedit

-## -##% endif diff --git a/lms/templates/problem.html b/lms/templates/problem.html index a78a1042a6..6363274d24 100644 --- a/lms/templates/problem.html +++ b/lms/templates/problem.html @@ -4,12 +4,6 @@ % if problem['weight'] != 1: : ${ problem['weight'] } points % endif - - % if settings.QUICKEDIT: -
- Quick Edit Problem -
- % endif