From 3d925f29ee1e81e8119eda36d9ee8e8c6dd3c639 Mon Sep 17 00:00:00 2001 From: ichuang Date: Tue, 29 May 2012 23:32:02 -0400 Subject: [PATCH] new "jumpto": go directly to a specific problem. changes made to urls, courseware.{views,module_render}, comments added to seq_module --- djangoapps/courseware/module_render.py | 28 +++++++- djangoapps/courseware/modules/seq_module.py | 3 +- djangoapps/courseware/views.py | 73 +++++++++++++++++++-- urls.py | 2 + 4 files changed, 98 insertions(+), 8 deletions(-) diff --git a/djangoapps/courseware/module_render.py b/djangoapps/courseware/module_render.py index 68b6e63ebb..6376f0c10d 100644 --- a/djangoapps/courseware/module_render.py +++ b/djangoapps/courseware/module_render.py @@ -80,8 +80,7 @@ def grade_histogram(module_id): return [] return grades -def render_x_module(user, request, xml_module, module_object_preload): - ''' Generic module for extensions. This renders to HTML. ''' +def get_state_from_module_object_preload(user, xml_module, module_object_preload): # Check if problem has an instance in DB module_type=xml_module.tag module_class=courseware.modules.get_module_class(module_type) @@ -97,6 +96,29 @@ def render_x_module(user, request, xml_module, module_object_preload): state=None else: state = smod.state + + return smod, state + +def render_x_module(user, request, xml_module, module_object_preload): + ''' Generic module for extensions. This renders to HTML. + + modules include sequential, vertical, problem, video, html + + Note that modules can recurse. problems, video, html, can be inside sequential or vertical. + + Arguments: + + - user : current django User + - request : current django HTTPrequest + - xml_module : lxml etree of xml subtree for the current module + - module_object_preload : list of StudentModule objects, one of which may match this module type and id + + ''' + module_type=xml_module.tag + module_class=courseware.modules.get_module_class(module_type) + module_id=xml_module.get('id') #module_class.id_attribute) or "" + + smod, state = get_state_from_module_object_preload(user, xml_module, module_object_preload) # get coursename if stored coursename = multicourse_settings.get_coursename_from_request(request) @@ -136,7 +158,7 @@ def render_x_module(user, request, xml_module, module_object_preload): destory_js = instance.get_destroy_js() # special extra information about each problem, only for users who are staff - if user.is_staff: + if False and user.is_staff: histogram = grade_histogram(module_id) render_histogram = len(histogram) > 0 content=content+render_to_string("staff_problem_info.html", {'xml':etree.tostring(xml_module), diff --git a/djangoapps/courseware/modules/seq_module.py b/djangoapps/courseware/modules/seq_module.py index 00350f0c62..adce633885 100644 --- a/djangoapps/courseware/modules/seq_module.py +++ b/djangoapps/courseware/modules/seq_module.py @@ -34,7 +34,8 @@ class Module(XModule): self.render() return self.destroy_js - def handle_ajax(self, dispatch, get): + def handle_ajax(self, dispatch, get): # TODO: bounds checking + ''' get = request.POST instance ''' if dispatch=='goto_position': self.position = int(get['position']) return json.dumps({'success':True}) diff --git a/djangoapps/courseware/views.py b/djangoapps/courseware/views.py index 10432ef7b3..daae47e3ce 100644 --- a/djangoapps/courseware/views.py +++ b/djangoapps/courseware/views.py @@ -17,7 +17,7 @@ from django.views.decorators.cache import cache_control from lxml import etree -from module_render import render_module, make_track_function, I4xSystem +from module_render import render_module, make_track_function, I4xSystem, get_state_from_module_object_preload from models import StudentModule from student.models import UserProfile from util.views import accepts @@ -151,8 +151,17 @@ def render_section(request, section): @ensure_csrf_cookie @cache_control(no_cache=True, no_store=True, must_revalidate=True) -def index(request, course=None, chapter="Using the System", section="Hints"): - ''' Displays courseware accordion, and any associated content. +def index(request, course=None, chapter="Using the System", section="Hints",position=None): + ''' Displays courseware accordion, and any associated content. + + Arguments: + + - request : HTTP request + - course : coursename (str) + - chapter : chapter name (str) + - section : section name (str) + - position : position in sequence, ie of module (int) + ''' user = request.user if not settings.COURSEWARE_ENABLED: @@ -181,17 +190,20 @@ def index(request, course=None, chapter="Using the System", section="Hints"): request.session['coursename'] = course # keep track of current course being viewed in django's request.session try: + # this is the course.xml etree dom = content_parser.course_file(user,course) # also pass course to it, for course-specific XML path except: log.exception("Unable to parse courseware xml") return render_to_response('courseware-error.html', {}) + # this is the module's parent's etree dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]", course=course, chapter=chapter, section=section) if len(dom_module) == 0: module = None else: + # this is the module's etree module = dom_module[0] module_ids = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]//@id", @@ -203,6 +215,21 @@ def index(request, course=None, chapter="Using the System", section="Hints"): else: module_object_preload = [] + if position and module and module.tag=='sequential': + smod, state = get_state_from_module_object_preload(user, module, module_object_preload) + newstate = json.dumps({ 'position':position }) + if smod: + smod.state = newstate + elif user.is_authenticated(): + smod=StudentModule(student=user, + module_type = module.tag, + module_id= module.get('id'), + state = newstate) + smod.save() + # now regenerate module_object_preload + module_object_preload = list(StudentModule.objects.filter(student=user, + module_id__in=module_ids)) + context = { 'csrf': csrf(request)['csrf_token'], 'accordion': render_accordion(request, course, chapter, section), @@ -210,7 +237,7 @@ def index(request, course=None, chapter="Using the System", section="Hints"): } try: - module = render_module(user, request, module, module_object_preload) + module = render_module(user, request, module, module_object_preload) # ugh - shouldn't overload module except: log.exception("Unable to load module") context.update({ @@ -302,6 +329,44 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): # Return whatever the module wanted to return to the client/caller return HttpResponse(ajax_return) +def jump_to(request, probname=None): + ''' + Jump to viewing a specific problem. The problem is specified by a problem name - currently the filename (minus .xml) + of the problem. Maybe this should change to a more generic tag, eg "name" given as an attribute in . + + We do the jump by (1) reading course.xml to find the first instance of with the given filename, then + (2) finding the parent element of the problem, then (3) rendering that parent element with a specific computed position + value (if it is ). + + ''' + # get coursename if stored + coursename = multicourse_settings.get_coursename_from_request(request) + + # begin by getting course.xml tree + xml = content_parser.course_file(request.user,coursename) + + # look for problem of given name + pxml = xml.xpath('//problem[@filename="%s"]' % probname) + if pxml: pxml = pxml[0] + + # get the parent element + parent = pxml.getparent() + + # figure out chapter and section names + chapter = None + section = None + branch = parent + for k in range(4): # max depth of recursion + if branch.tag=='section': section = branch.get('name') + if branch.tag=='chapter': chapter = branch.get('name') + branch = branch.getparent() + + position = None + if parent.tag=='sequential': + position = parent.index(pxml)+1 # position in sequence + + return index(request,course=coursename,chapter=chapter,section=section,position=position) + def quickedit(request, id=None, qetemplate='quickedit.html',coursename=None): ''' quick-edit capa problem. diff --git a/urls.py b/urls.py index 92ee88e69a..febb842c3a 100644 --- a/urls.py +++ b/urls.py @@ -51,9 +51,11 @@ if settings.COURSEWARE_ENABLED: url(r'^info$', 'util.views.info'), url(r'^wiki/', include('simplewiki.urls')), url(r'^masquerade/', include('masquerade.urls')), + url(r'^courseware/(?P[^/]*)/(?P[^/]*)/(?P
[^/]*)/(?P[^/]*)$', 'courseware.views.index'), url(r'^courseware/(?P[^/]*)/(?P[^/]*)/(?P
[^/]*)/$', 'courseware.views.index', name="courseware_section"), url(r'^courseware/(?P[^/]*)/(?P[^/]*)/$', 'courseware.views.index', name="courseware_chapter"), url(r'^courseware/(?P[^/]*)/$', 'courseware.views.index', name="courseware_course"), + url(r'^jumpto/(?P[^/]+)/$', 'courseware.views.jump_to'), url(r'^section/(?P
[^/]*)/$', 'courseware.views.render_section'), url(r'^modx/(?P[^/]*)/(?P[^/]*)/(?P[^/]*)$', 'courseware.views.modx_dispatch'), #reset_problem'), url(r'^profile$', 'courseware.views.profile'),