diff --git a/djangoapps/courseware/capa/capa_problem.py b/djangoapps/courseware/capa/capa_problem.py
index c5a81e8100..9835b598b2 100644
--- a/djangoapps/courseware/capa/capa_problem.py
+++ b/djangoapps/courseware/capa/capa_problem.py
@@ -53,13 +53,12 @@ html_special_response = {"textline":textline.render,
"schematic":schematic.render}
class LoncapaProblem(object):
- def __init__(self, filename, id=None, state=None, seed=None):
+ def __init__(self, fileobject, id=None, state=None, seed=None):
## Initialize class variables from state
self.seed = None
self.student_answers = dict()
self.correct_map = dict()
self.done = False
- self.filename = filename
if seed != None:
self.seed = seed
@@ -69,7 +68,6 @@ class LoncapaProblem(object):
else:
print "NO ID"
raise Exception("This should never happen (183)")
- #self.problem_id = filename
if state:
if 'seed' in state:
@@ -81,17 +79,12 @@ class LoncapaProblem(object):
if 'done' in state:
self.done = state['done']
-# print self.seed
-
# TODO: Does this deplete the Linux entropy pool? Is this fast enough?
if not self.seed:
self.seed=struct.unpack('i', os.urandom(4))[0]
-# print filename, self.seed, seed
-
## Parse XML file
- #log.debug(u"LoncapaProblem() opening file {0}".format(filename))
- file_text = open(filename).read()
+ file_text = fileobject.read()
# Convert startouttext and endouttext to proper
# TODO: Do with XML operations
file_text = re.sub("startouttext\s*/","text",file_text)
diff --git a/djangoapps/courseware/module_render.py b/djangoapps/courseware/module_render.py
index 2924aec9df..ac76eb08ae 100644
--- a/djangoapps/courseware/module_render.py
+++ b/djangoapps/courseware/module_render.py
@@ -18,8 +18,12 @@ from django.http import HttpResponse
from django.shortcuts import redirect
from django.template import Context
from django.template import Context, loader
+
+from fs.osfs import OSFS
+
from mitxmako.shortcuts import render_to_response, render_to_string
+
from models import StudentModule
from student.models import UserProfile
import track.views
@@ -30,6 +34,14 @@ import courseware.modules
log = logging.getLogger("mitx.courseware")
+class I4xSystem(object):
+ def __init__(self, ajax_url, track_function, render_function, filestore=None):
+ self.ajax_url = ajax_url
+ self.track_function = track_function
+ self.filestore = OSFS(settings.DATA_DIR)
+ self.render_function = render_function
+ self.exception404 = Http404
+
def object_cache(cache, user, module_type, module_id):
# We don't look up on user -- all queries include user
# Additional lookup would require a DB hit the way Django
@@ -76,12 +88,15 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
xml = content_parser.module_xml(request.user, module, 'id', id)
# Create the module
- instance=courseware.modules.get_module_class(module)(xml,
+ system = I4xSystem(track_function = make_track_function(request),
+ render_function = None,
+ ajax_url = ajax_url,
+ filestore = None
+ )
+ instance=courseware.modules.get_module_class(module)(system,
+ xml,
id,
- ajax_url=ajax_url,
- state=oldstate,
- track_function = make_track_function(request),
- render_function = None)
+ state=oldstate)
# Let the module handle the AJAX
ajax_return=instance.handle_ajax(dispatch, request.POST)
# Save the state back to the database
@@ -128,12 +143,15 @@ def render_x_module(user, request, xml_module, module_object_preload):
# Create a new instance
ajax_url = '/modx/'+module_type+'/'+module_id+'/'
- instance=module_class(etree.tostring(xml_module),
+ system = I4xSystem(track_function = make_track_function(request),
+ render_function = lambda x: render_module(user, request, x, module_object_preload),
+ ajax_url = ajax_url,
+ filestore = None
+ )
+ instance=module_class(system,
+ etree.tostring(xml_module),
module_id,
- ajax_url=ajax_url,
- state=state,
- track_function = make_track_function(request),
- render_function = lambda x: render_module(user, request, x, module_object_preload))
+ state=state)
# If instance wasn't already in the database, create it
if not smod:
diff --git a/djangoapps/courseware/modules/capa_module.py b/djangoapps/courseware/modules/capa_module.py
index 86958dcf1c..5c2f6be5c3 100644
--- a/djangoapps/courseware/modules/capa_module.py
+++ b/djangoapps/courseware/modules/capa_module.py
@@ -16,9 +16,7 @@ import traceback
from lxml import etree
## TODO: Abstract out from Django
-from django.conf import settings
-from mitxmako.shortcuts import render_to_response, render_to_string
-from django.http import Http404
+from mitxmako.shortcuts import render_to_string
from x_module import XModule
from courseware.capa.capa_problem import LoncapaProblem, StudentInputError
@@ -92,7 +90,6 @@ class Module(XModule):
# User submitted a problem, and hasn't reset. We don't want
# more submissions.
if self.lcp.done and self.rerandomize == "always":
- #print "!"
check_button = False
save_button = False
@@ -131,8 +128,8 @@ class Module(XModule):
return html
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None, meta = None):
- XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
+ def __init__(self, system, xml, item_id, state=None):
+ XModule.__init__(self, system, xml, item_id, state)
self.attempts = 0
self.max_attempts = None
@@ -185,15 +182,14 @@ class Module(XModule):
if state!=None and 'attempts' in state:
self.attempts=state['attempts']
- self.filename=content_parser.item(dom2.xpath('/problem/@filename'))
- filename=settings.DATA_DIR+"/problems/"+self.filename+".xml"
+ self.filename="problems/"+content_parser.item(dom2.xpath('/problem/@filename'))+".xml"
self.name=content_parser.item(dom2.xpath('/problem/@name'))
self.weight=content_parser.item(dom2.xpath('/problem/@weight'))
if self.rerandomize == 'never':
seed = 1
else:
seed = None
- self.lcp=LoncapaProblem(filename, self.item_id, state, seed = seed)
+ self.lcp=LoncapaProblem(self.filestore.open(self.filename), self.item_id, state, seed = seed)
def handle_ajax(self, dispatch, get):
if dispatch=='problem_get':
@@ -242,16 +238,15 @@ class Module(XModule):
if self.show_answer == 'closed' and not self.closed():
return False
print "aa", self.show_answer
- raise Http404
+ raise self.system.exception404 #TODO: Not 404
def get_answer(self, get):
if not self.answer_available():
- raise Http404
+ raise self.system.exception404
else:
return json.dumps(self.lcp.get_question_answers(),
cls=ComplexEncoder)
-
# Figure out if we should move these to capa_problem?
def get_problem(self, get):
''' Same as get_problem_html -- if we want to reconfirm we
@@ -270,41 +265,33 @@ class Module(XModule):
for key in get:
answers['_'.join(key.split('_')[1:])]=get[key]
-# print "XXX", answers, get
-
event_info['answers']=answers
# Too late. Cannot submit
if self.closed():
event_info['failure']='closed'
self.tracker('save_problem_check_fail', event_info)
- print "cp"
- raise Http404
+ raise self.system.exception404
# Problem submitted. Student should reset before checking
# again.
if self.lcp.done and self.rerandomize == "always":
event_info['failure']='unreset'
self.tracker('save_problem_check_fail', event_info)
- print "cpdr"
- raise Http404
+ raise self.system.exception404
try:
old_state = self.lcp.get_state()
lcp_id = self.lcp.problem_id
- filename = self.lcp.filename
correct_map = self.lcp.grade_answers(answers)
except StudentInputError as inst:
- self.lcp = LoncapaProblem(filename, id=lcp_id, state=old_state)
+ self.lcp = LoncapaProblem(self.filestore.open(self.filename), id=lcp_id, state=old_state)
traceback.print_exc()
-# print {'error':sys.exc_info(),
-# 'answers':answers,
-# 'seed':self.lcp.seed,
-# 'filename':self.lcp.filename}
return json.dumps({'success':inst.message})
except:
- self.lcp = LoncapaProblem(filename, id=lcp_id, state=old_state)
+ self.lcp = LoncapaProblem(self.filestore.open(self.filename), id=lcp_id, state=old_state)
traceback.print_exc()
+ raise
return json.dumps({'success':'Unknown Error'})
@@ -382,8 +369,8 @@ class Module(XModule):
self.lcp.questions=dict() # Detailed info about questions in problem instance. TODO: Should be by id and not lid.
self.lcp.seed=None
- filename=settings.DATA_DIR+"problems/"+self.filename+".xml"
- self.lcp=LoncapaProblem(filename, self.item_id, self.lcp.get_state())
+ filename="problems/"+self.filename+".xml"
+ self.lcp=LoncapaProblem(self.filestore.open(filename), self.item_id, self.lcp.get_state())
event_info['new_state']=self.lcp.get_state()
self.tracker('reset_problem', event_info)
diff --git a/djangoapps/courseware/modules/html_module.py b/djangoapps/courseware/modules/html_module.py
index 4194f73e74..77bcbb4bbc 100644
--- a/djangoapps/courseware/modules/html_module.py
+++ b/djangoapps/courseware/modules/html_module.py
@@ -1,7 +1,5 @@
import json
-## TODO: Abstract out from Django
-from django.conf import settings
from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule
@@ -24,13 +22,13 @@ class Module(XModule):
textlist=[i for i in textlist if type(i)==str]
return "".join(textlist)
try:
- filename=settings.DATA_DIR+"html/"+self.filename
- return open(filename).read()
+ filename="html/"+self.filename
+ return self.filestore.open(filename).read()
except: # For backwards compatibility. TODO: Remove
return render_to_string(self.filename, {'id': self.item_id})
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
- XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
+ def __init__(self, system, xml, item_id, state=None):
+ XModule.__init__(self, system, xml, item_id, state)
xmltree=etree.fromstring(xml)
self.filename = None
filename_l=xmltree.xpath("/html/@filename")
diff --git a/djangoapps/courseware/modules/schematic_module.py b/djangoapps/courseware/modules/schematic_module.py
index e253f1acc6..5fef265e01 100644
--- a/djangoapps/courseware/modules/schematic_module.py
+++ b/djangoapps/courseware/modules/schematic_module.py
@@ -19,6 +19,6 @@ class Module(XModule):
def get_html(self):
return ''.format(item_id=self.item_id)
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, render_function = None):
- XModule.__init__(self, xml, item_id, ajax_url, track_url, state, render_function)
+ def __init__(self, system, xml, item_id, state=None):
+ XModule.__init__(self, system, xml, item_id, state)
diff --git a/djangoapps/courseware/modules/seq_module.py b/djangoapps/courseware/modules/seq_module.py
index 80e0b4c7bf..161c95b604 100644
--- a/djangoapps/courseware/modules/seq_module.py
+++ b/djangoapps/courseware/modules/seq_module.py
@@ -2,9 +2,7 @@ import json
from lxml import etree
-## TODO: Abstract out from Django
-from django.http import Http404
-from mitxmako.shortcuts import render_to_string
+from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule
@@ -37,12 +35,10 @@ class Module(XModule):
return self.destroy_js
def handle_ajax(self, dispatch, get):
- print "GET", get
- print "DISPATCH", dispatch
if dispatch=='goto_position':
self.position = int(get['position'])
return json.dumps({'success':True})
- raise Http404()
+ raise self.system.exception404
def render(self):
if self.rendered:
@@ -106,9 +102,8 @@ class Module(XModule):
self.rendered = True
-
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
- XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
+ def __init__(self, system, xml, item_id, state=None):
+ XModule.__init__(self, system, xml, item_id, state)
self.xmltree=etree.fromstring(xml)
self.position = 1
diff --git a/djangoapps/courseware/modules/template_module.py b/djangoapps/courseware/modules/template_module.py
index d9dbb613f0..41556eb9d4 100644
--- a/djangoapps/courseware/modules/template_module.py
+++ b/djangoapps/courseware/modules/template_module.py
@@ -14,16 +14,16 @@ class Module(XModule):
@classmethod
def get_xml_tags(c):
+ ## TODO: Abstract out from filesystem
tags = os.listdir(settings.DATA_DIR+'/custom_tags')
return tags
def get_html(self):
return self.html
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
- XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
+ def __init__(self, system, xml, item_id, state=None):
+ XModule.__init__(self, system, xml, item_id, state)
xmltree = etree.fromstring(xml)
filename = xmltree.tag
params = dict(xmltree.items())
-# print params
self.html = render_to_string(filename, params, namespace = 'custom_tags')
diff --git a/djangoapps/courseware/modules/vertical_module.py b/djangoapps/courseware/modules/vertical_module.py
index c068cb9a76..f64e45fe7f 100644
--- a/djangoapps/courseware/modules/vertical_module.py
+++ b/djangoapps/courseware/modules/vertical_module.py
@@ -1,7 +1,5 @@
import json
-## TODO: Abstract out from Django
-from django.conf import settings
from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule
@@ -26,8 +24,9 @@ class Module(XModule):
def get_destroy_js(self):
return self.destroy_js_text
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
- XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
+
+ def __init__(self, system, xml, item_id, state=None):
+ XModule.__init__(self, system, xml, item_id, state)
xmltree=etree.fromstring(xml)
self.contents=[(e.get("name"),self.render_function(e)) \
for e in xmltree]
diff --git a/djangoapps/courseware/modules/video_module.py b/djangoapps/courseware/modules/video_module.py
index f116853447..c678838f2b 100644
--- a/djangoapps/courseware/modules/video_module.py
+++ b/djangoapps/courseware/modules/video_module.py
@@ -3,9 +3,7 @@ import logging
from lxml import etree
-## TODO: Abstract out from Django
-from django.http import Http404
-from mitxmako.shortcuts import render_to_string
+from mitxmako.shortcuts import render_to_response, render_to_string
from x_module import XModule
@@ -58,8 +56,8 @@ class Module(XModule):
def get_destroy_js(self):
return "videoDestroy(\"{0}\");".format(self.item_id)+self.annotations_destroy
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
- XModule.__init__(self, xml, item_id, ajax_url, track_url, state, track_function, render_function)
+ def __init__(self, system, xml, item_id, state=None):
+ XModule.__init__(self, system, xml, item_id, state)
xmltree=etree.fromstring(xml)
self.youtube = xmltree.get('youtube')
self.name = xmltree.get('name')
diff --git a/djangoapps/courseware/modules/x_module.py b/djangoapps/courseware/modules/x_module.py
index 4a379253c4..b21894b36b 100644
--- a/djangoapps/courseware/modules/x_module.py
+++ b/djangoapps/courseware/modules/x_module.py
@@ -45,13 +45,14 @@ class XModule(object):
get is a dictionary-like object '''
return ""
- def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None, track_function=None, render_function = None):
+ def __init__(self, system, xml, item_id, track_url=None, state=None):
''' In most cases, you must pass state or xml'''
self.xml = xml
self.item_id = item_id
- self.ajax_url = ajax_url
- self.track_url = track_url
self.state = state
- self.tracker = track_function
- self.render_function = render_function
+ self.ajax_url = system.ajax_url
+ self.tracker = system.track_function
+ self.filestore = system.filestore
+ self.render_function = system.render_function
+ self.system = system