diff --git a/djangoapps/courseware/module_render.py b/djangoapps/courseware/module_render.py index 278d19fd2c..ed3429d747 100644 --- a/djangoapps/courseware/module_render.py +++ b/djangoapps/courseware/module_render.py @@ -78,9 +78,8 @@ 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. ''' - # Check if problem has an instance in DB + +def get_module(user, request, xml_module, module_object_preload): 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 "" @@ -128,6 +127,15 @@ def render_x_module(user, request, xml_module, module_object_preload): smod.save() module_object_preload.append(smod) + return smod + +def render_x_module(user, request, xml_module, module_object_preload): + ''' Generic module for extensions. This renders to HTML. ''' + if module==None : + return {"content":""} + + smod = get_module(user, request, xml_module, module_object_preload) + # Grab content content = instance.get_html() init_js = instance.get_init_js() @@ -153,6 +161,78 @@ def render_x_module(user, request, xml_module, module_object_preload): def render_module(user, request, module, module_object_preload): ''' Generic dispatch for internal modules. ''' - if module==None : - return {"content":""} return render_x_module(user, request, module, module_object_preload) + + +def modx_dispatch(request, module=None, dispatch=None, id=None): + ''' Generic view for extensions. ''' + if not request.user.is_authenticated(): + return redirect('/') + + # Grab the student information for the module from the database + s = StudentModule.objects.filter(student=request.user, + module_id=id) + #s = StudentModule.get_with_caching(request.user, id) + if len(s) == 0 or s is None: + log.debug("Couldnt find module for user and id " + str(module) + " " + str(request.user) + " "+ str(id)) + raise Http404 + s = s[0] + + oldgrade = s.grade + oldstate = s.state + + dispatch=dispatch.split('?')[0] + + ajax_url = settings.MITX_ROOT_URL + '/modx/'+module+'/'+id+'/' + + # get coursename if stored + coursename = multicourse_settings.get_coursename_from_request(request) + + if coursename and settings.ENABLE_MULTICOURSE: + xp = multicourse_settings.get_course_xmlpath(coursename) # path to XML for the course + data_root = settings.DATA_DIR + xp + else: + data_root = settings.DATA_DIR + + # Grab the XML corresponding to the request from course.xml + try: + xml = content_parser.module_xml(request.user, module, 'id', id, coursename) + except: + log.exception("Unable to load module during ajax call") + if accepts(request, 'text/html'): + return render_to_response("module-error.html", {}) + else: + response = HttpResponse(json.dumps({'success': "We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible"})) + return response + + # Create the module + system = I4xSystem(track_function = make_track_function(request), + render_function = None, + ajax_url = ajax_url, + filestore = OSFS(data_root), + ) + + try: + instance=courseware.modules.get_module_class(module)(system, + xml, + id, + state=oldstate) + except: + log.exception("Unable to load module instance during ajax call") + if accepts(request, 'text/html'): + return render_to_response("module-error.html", {}) + else: + response = HttpResponse(json.dumps({'success': "We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible"})) + return response + + # Let the module handle the AJAX + ajax_return=instance.handle_ajax(dispatch, request.POST) + # Save the state back to the database + s.state=instance.get_state() + if instance.get_score(): + s.grade=instance.get_score()['score'] + if s.grade != oldgrade or s.state != oldstate: + s.save() + # Return whatever the module wanted to return to the client/caller + return HttpResponse(ajax_return) + diff --git a/djangoapps/courseware/modules/capa_module.py b/djangoapps/courseware/modules/capa_module.py index 7d42cfb250..058b5f5454 100644 --- a/djangoapps/courseware/modules/capa_module.py +++ b/djangoapps/courseware/modules/capa_module.py @@ -31,6 +31,9 @@ class ComplexEncoder(json.JSONEncoder): return "{real:.7g}{imag:+.7g}*j".format(real = obj.real,imag = obj.imag) return json.JSONEncoder.default(self, obj) +class ModuleDescriptor(XModuleDescriptor): + pass + class Module(XModule): ''' Interface between capa_problem and x_module. Originally a hack meant to be refactored out, but it seems to be serving a useful diff --git a/djangoapps/courseware/modules/html_module.py b/djangoapps/courseware/modules/html_module.py index 77bcbb4bbc..3b62df0390 100644 --- a/djangoapps/courseware/modules/html_module.py +++ b/djangoapps/courseware/modules/html_module.py @@ -5,6 +5,9 @@ from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule from lxml import etree +class ModuleDescriptor(XModuleDescriptor): + pass + class Module(XModule): id_attribute = 'filename' diff --git a/djangoapps/courseware/modules/schematic_module.py b/djangoapps/courseware/modules/schematic_module.py index 5fef265e01..1643737e4a 100644 --- a/djangoapps/courseware/modules/schematic_module.py +++ b/djangoapps/courseware/modules/schematic_module.py @@ -6,6 +6,9 @@ from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule +class ModuleDescriptor(XModuleDescriptor): + pass + class Module(XModule): id_attribute = 'id' diff --git a/djangoapps/courseware/modules/seq_module.py b/djangoapps/courseware/modules/seq_module.py index af41d0e8da..42508295db 100644 --- a/djangoapps/courseware/modules/seq_module.py +++ b/djangoapps/courseware/modules/seq_module.py @@ -10,6 +10,9 @@ from x_module import XModule # OBSOLETE: This obsoletes 'type' class_priority = ['video', 'problem'] +class ModuleDescriptor(XModuleDescriptor): + pass + class Module(XModule): ''' Layout module which lays out content in a temporal sequence ''' @@ -66,8 +69,7 @@ class Module(XModule): self.titles = json.dumps(["\n".join([i.get("name").strip() for i in e.iter() if i.get("name") != None]) \ for e in self.xmltree]) - self.contents = [j(self.render_function(e)) \ - for e in self.xmltree] + self.contents = self.rendered_children(self) print self.titles diff --git a/djangoapps/courseware/modules/template_module.py b/djangoapps/courseware/modules/template_module.py index a8899f985c..c779691cc1 100644 --- a/djangoapps/courseware/modules/template_module.py +++ b/djangoapps/courseware/modules/template_module.py @@ -6,6 +6,9 @@ from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule from lxml import etree +class ModuleDescriptor(XModuleDescriptor): + pass + class Module(XModule): def get_state(self): return json.dumps({ }) diff --git a/djangoapps/courseware/modules/vertical_module.py b/djangoapps/courseware/modules/vertical_module.py index e57a58e33e..519ed755ea 100644 --- a/djangoapps/courseware/modules/vertical_module.py +++ b/djangoapps/courseware/modules/vertical_module.py @@ -5,6 +5,9 @@ from mitxmako.shortcuts import render_to_response, render_to_string from x_module import XModule from lxml import etree +class ModuleDescriptor(XModuleDescriptor): + pass + class Module(XModule): id_attribute = 'id' diff --git a/djangoapps/courseware/modules/video_module.py b/djangoapps/courseware/modules/video_module.py index c678838f2b..12136cf7f2 100644 --- a/djangoapps/courseware/modules/video_module.py +++ b/djangoapps/courseware/modules/video_module.py @@ -9,6 +9,9 @@ from x_module import XModule log = logging.getLogger("mitx.courseware.modules") +class ModuleDescriptor(XModuleDescriptor): + pass + class Module(XModule): id_attribute = 'youtube' video_time = 0 diff --git a/djangoapps/courseware/modules/x_module.py b/djangoapps/courseware/modules/x_module.py index b475fd0280..ae6822da1d 100644 --- a/djangoapps/courseware/modules/x_module.py +++ b/djangoapps/courseware/modules/x_module.py @@ -24,6 +24,21 @@ class XModule(object): or a CAPA input type ''' return ['xmodule'] + def get_name(): + name = self.__xmltree.get(name) + if name: + return name + else: + raise "We should iterate through children and find a default name" + + def rendered_children(self): + ''' + Render all children. + This really ought to return a list of xmodules, instead of dictionaries + ''' + children = [render_function(e) for e in self.__xmltree] + return children + def __init__(self, system = None, xml = None, item_id = None, json = None, track_url=None, state=None): ''' In most cases, you must pass state or xml''' @@ -38,6 +53,8 @@ class XModule(object): self.json = json self.item_id = item_id self.state = state + + self.__xmltree = etree.fromstring(xml) # PRIVATE if system: ## These are temporary; we really should go @@ -102,14 +119,24 @@ class XModule(object): get is a dictionary-like object ''' return "" - ### Functions used in the CMS + +class XModuleDescriptor(object): + def __init__(self, xml = None, json = None): + if not xml and not json: + raise "XModuleDescriptor must be initalized with XML or JSON" + if not xml: + raise NotImplementedError("Code does not have support for JSON yet") + + self.xml = xml + self.json = json + def get_xml(self): ''' For conversions between JSON and legacy XML representations. ''' if self.xml: return self.xml else: - raise NotImplementedError + raise NotImplementedError("JSON->XML Translation not implemented") def get_json(self): ''' For conversions between JSON and legacy XML representations. @@ -118,14 +145,14 @@ class XModule(object): raise NotImplementedError return self.json # TODO: Return context as well -- files, etc. else: - raise NotImplementedError + raise NotImplementedError("XML->JSON Translation not implemented") - def handle_cms_json(self): - raise NotImplementedError + #def handle_cms_json(self): + # raise NotImplementedError - def render(self, size): - ''' Size: [thumbnail, small, full] - Small ==> what we drag around - Full ==> what we edit - ''' - raise NotImplementedError + #def render(self, size): + # ''' Size: [thumbnail, small, full] + # Small ==> what we drag around + # Full ==> what we edit + # ''' + # raise NotImplementedError diff --git a/djangoapps/courseware/views.py b/djangoapps/courseware/views.py index 014f759ed1..228a33461b 100644 --- a/djangoapps/courseware/views.py +++ b/djangoapps/courseware/views.py @@ -16,7 +16,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, modx_dispatch from models import StudentModule from student.models import UserProfile from util.views import accepts @@ -237,78 +237,6 @@ def index(request, course=None, chapter="Using the System", section="Hints"): return result -def modx_dispatch(request, module=None, dispatch=None, id=None): - ''' Generic view for extensions. ''' - if not request.user.is_authenticated(): - return redirect('/') - - # Grab the student information for the module from the database - s = StudentModule.objects.filter(student=request.user, - module_id=id) - #s = StudentModule.get_with_caching(request.user, id) - if len(s) == 0 or s is None: - log.debug("Couldnt find module for user and id " + str(module) + " " + str(request.user) + " "+ str(id)) - raise Http404 - s = s[0] - - oldgrade = s.grade - oldstate = s.state - - dispatch=dispatch.split('?')[0] - - ajax_url = settings.MITX_ROOT_URL + '/modx/'+module+'/'+id+'/' - - # get coursename if stored - coursename = multicourse_settings.get_coursename_from_request(request) - - if coursename and settings.ENABLE_MULTICOURSE: - xp = multicourse_settings.get_course_xmlpath(coursename) # path to XML for the course - data_root = settings.DATA_DIR + xp - else: - data_root = settings.DATA_DIR - - # Grab the XML corresponding to the request from course.xml - try: - xml = content_parser.module_xml(request.user, module, 'id', id, coursename) - except: - log.exception("Unable to load module during ajax call") - if accepts(request, 'text/html'): - return render_to_response("module-error.html", {}) - else: - response = HttpResponse(json.dumps({'success': "We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible"})) - return response - - # Create the module - system = I4xSystem(track_function = make_track_function(request), - render_function = None, - ajax_url = ajax_url, - filestore = OSFS(data_root), - ) - - try: - instance=courseware.modules.get_module_class(module)(system, - xml, - id, - state=oldstate) - except: - log.exception("Unable to load module instance during ajax call") - if accepts(request, 'text/html'): - return render_to_response("module-error.html", {}) - else: - response = HttpResponse(json.dumps({'success': "We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible"})) - return response - - # Let the module handle the AJAX - ajax_return=instance.handle_ajax(dispatch, request.POST) - # Save the state back to the database - s.state=instance.get_state() - if instance.get_score(): - s.grade=instance.get_score()['score'] - if s.grade != oldgrade or s.state != oldstate: - s.save() - # Return whatever the module wanted to return to the client/caller - return HttpResponse(ajax_return) - def quickedit(request, id=None): ''' quick-edit capa problem. diff --git a/run.sh b/run.sh index d63ed291f0..0c65a4a72c 100755 --- a/run.sh +++ b/run.sh @@ -1 +1 @@ -django-admin.py runserver --settings=envs.dev --pythonpath=. +django-admin runserver --settings=envs.dev --pythonpath=.