Refactoring into module, part 1
This commit is contained in:
@@ -4,26 +4,48 @@
|
||||
import random, numpy, math, scipy, sys, StringIO, os, struct, json
|
||||
from x_module import XModule
|
||||
|
||||
from capa_problem import LoncapaProblem
|
||||
|
||||
from xml.dom.minidom import parse, parseString
|
||||
|
||||
class LoncapaProblem(XModule):
|
||||
## TODO: Abstract out from Django
|
||||
from django.conf import settings
|
||||
from djangomako.shortcuts import render_to_response, render_to_string
|
||||
|
||||
class LoncapaModule(XModule):
|
||||
xml_tags=["problem"]
|
||||
id_attribute="filename"
|
||||
|
||||
def get_state(self):
|
||||
print "got"
|
||||
return self.lcp.get_state()
|
||||
|
||||
def get_score(self):
|
||||
return self.lcp.get_score()
|
||||
|
||||
def max_score(self):
|
||||
return len(lcp.questions)
|
||||
|
||||
def get_html(self):
|
||||
|
||||
def handle_ajax(self, json):
|
||||
|
||||
def __init__(self, filename, id=None, state=None):
|
||||
inner_html=self.lcp.get_html()
|
||||
content={'name':self.name,
|
||||
'html':inner_html}
|
||||
return render_to_string('problem.html',
|
||||
{'problem':content, 'id':self.filename})
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
p=LoncapaProblem('<problem name="Problem 1: Resistive Divider" filename="resistor" />')
|
||||
|
||||
print p.getHtml()
|
||||
print p.getContext()
|
||||
print p.getSeed()
|
||||
# Chef and puppot
|
||||
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None):
|
||||
XModule.__init__(self, xml, item_id, ajax_url, track_url, state)
|
||||
dom=parseString(xml)
|
||||
node=dom.childNodes[0]
|
||||
self.filename=node.getAttribute("filename")
|
||||
filename=settings.DATA_DIR+self.filename+".xml"
|
||||
self.name=node.getAttribute("name")
|
||||
print state
|
||||
self.lcp=LoncapaProblem(filename, item_id, state)
|
||||
|
||||
# Temporary
|
||||
|
||||
def check_problem(self, get):
|
||||
pass
|
||||
|
||||
@@ -26,16 +26,10 @@ class LoncapaProblem():
|
||||
return {'score':correct,
|
||||
'total':len(self.questions)}
|
||||
|
||||
def max_score(self):
|
||||
pass
|
||||
|
||||
def get_html(self):
|
||||
''' Return the HTML of the question '''
|
||||
return self.text
|
||||
|
||||
def handle_ajax(self, json):
|
||||
pass
|
||||
|
||||
def __init__(self, filename, id=None, state=None):
|
||||
''' Create a new problem of the type defined in filename.
|
||||
By default, this will generate a random problem. Passing
|
||||
@@ -71,7 +65,7 @@ class LoncapaProblem():
|
||||
ot=False ## Are we in an outtext context?
|
||||
|
||||
for e in dom.childNodes:
|
||||
if e.localName=='script' and context==None:
|
||||
if e.localName=='script':
|
||||
exec e.childNodes[0].data in g,self.context
|
||||
if e.localName=='endouttext':
|
||||
ot=False
|
||||
@@ -85,7 +79,7 @@ class LoncapaProblem():
|
||||
|
||||
self.text=buf.getvalue()
|
||||
self.text=self.contextualize_text(self.text)
|
||||
|
||||
self.filename=filename
|
||||
|
||||
text=""
|
||||
context={} # Execution context from loncapa/python
|
||||
|
||||
25
courseware/content_parser.py
Normal file
25
courseware/content_parser.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from django.conf import settings
|
||||
from xml.dom.minidom import parse, parseString
|
||||
|
||||
|
||||
def toc_from_xml(active_chapter,active_section):
|
||||
dom=parse(settings.DATA_DIR+'course.xml')
|
||||
|
||||
course = dom.getElementsByTagName('course')[0]
|
||||
name=course.getAttribute("name")
|
||||
chapters = course.getElementsByTagName('chapter')
|
||||
ch=list()
|
||||
for c in chapters:
|
||||
sections=list()
|
||||
for s in c.getElementsByTagName('section'):
|
||||
sections.append({'name':s.getAttribute("name"),
|
||||
'time':s.getAttribute("time"),
|
||||
'format':s.getAttribute("format"),
|
||||
'due':s.getAttribute("due"),
|
||||
'active':(c.getAttribute("name")==active_chapter and \
|
||||
s.getAttribute("name")==active_section)})
|
||||
ch.append({'name':c.getAttribute("name"),
|
||||
'sections':sections,
|
||||
'active':(c.getAttribute("name")==active_chapter)})
|
||||
return ch
|
||||
|
||||
@@ -44,10 +44,13 @@ class StudentModule(models.Model):
|
||||
state = models.TextField(null=True, blank=True)
|
||||
grade = models.FloatField(null=True, blank=True)
|
||||
student = models.ForeignKey(User)
|
||||
MODULE_TYPES = (('hw','homework'),)
|
||||
module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='hw')
|
||||
module_id = models.CharField(max_length=255) # Filename
|
||||
MODULE_TYPES = (('problem','problem'),)
|
||||
module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='problem')
|
||||
module_id = models.CharField(max_length=255) # Filename for homeworks, etc.
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
modified = models.DateTimeField(auto_now=True)
|
||||
class Meta:
|
||||
unique_together = (('student', 'module_id'),)
|
||||
unique_together = (('student', 'module_id', 'module_type'),)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.module_type+'/'+self.student.username+"/"+self.module_id+'/'+str(self.state)[:20]
|
||||
|
||||
@@ -12,9 +12,11 @@ from django.shortcuts import redirect
|
||||
|
||||
import StringIO
|
||||
|
||||
from django.http import Http404
|
||||
|
||||
import urllib
|
||||
|
||||
import capa_problem
|
||||
import capa_module, capa_problem
|
||||
|
||||
from models import StudentModule
|
||||
|
||||
@@ -22,6 +24,8 @@ import urllib
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from content_parser import *
|
||||
|
||||
template_imports={'urllib':urllib}
|
||||
|
||||
def profile(request):
|
||||
@@ -49,9 +53,7 @@ def profile(request):
|
||||
correct=response.grade
|
||||
else:
|
||||
correct=0
|
||||
# CRITICAL TODO: Benchmark, and probably cache. We shouldn't recalculate this
|
||||
# every time. By modularity, this also belongs inside LoncapaProblem.
|
||||
total=len(capa_problem.LoncapaProblem(settings.DATA_DIR+id+'.xml', id=id).questions)
|
||||
total=capa_module.LoncapaModule(p, id=id).max_score()
|
||||
scores.append((int(correct),total))
|
||||
score={'course':course.getAttribute('name'),
|
||||
'section':s.getAttribute("name"),
|
||||
@@ -71,27 +73,6 @@ def profile(request):
|
||||
}
|
||||
return render_to_response('profile.html', context)
|
||||
|
||||
def toc_from_xml(active_chapter,active_section):
|
||||
dom=parse(settings.DATA_DIR+'course.xml')
|
||||
|
||||
course = dom.getElementsByTagName('course')[0]
|
||||
name=course.getAttribute("name")
|
||||
chapters = course.getElementsByTagName('chapter')
|
||||
ch=list()
|
||||
for c in chapters:
|
||||
sections=list()
|
||||
for s in c.getElementsByTagName('section'):
|
||||
sections.append({'name':s.getAttribute("name"),
|
||||
'time':s.getAttribute("time"),
|
||||
'format':s.getAttribute("format"),
|
||||
'due':s.getAttribute("due"),
|
||||
'active':(c.getAttribute("name")==active_chapter and \
|
||||
s.getAttribute("name")==active_section)})
|
||||
ch.append({'name':c.getAttribute("name"),
|
||||
'sections':sections,
|
||||
'active':(c.getAttribute("name")==active_chapter)})
|
||||
return ch
|
||||
|
||||
def render_accordion(request,course,chapter,section):
|
||||
''' Draws accordion. Takes current position in accordion as
|
||||
parameter. Returns (initialization_javascript, content)'''
|
||||
@@ -138,28 +119,43 @@ def vertical_module(request, module):
|
||||
return {'js':js,
|
||||
'content':render_to_string('vert_module.html',{'items':contents})}
|
||||
|
||||
def render_problem(request, filename):
|
||||
def render_x_module(request, xml_module):
|
||||
# Check if problem has an instance in DB
|
||||
s = StudentModule.objects.filter(student=request.user, module_id=filename)
|
||||
module_id=xml_module.getAttribute(capa_module.LoncapaModule.id_attribute)
|
||||
s = StudentModule.objects.filter(student=request.user, module_id=module_id)
|
||||
if len(s) == 0:
|
||||
# If not, create one, and return it
|
||||
problem=capa_problem.LoncapaProblem(settings.DATA_DIR+filename+'.xml', id=filename)
|
||||
# If not, create one, and save it
|
||||
problem=capa_module.LoncapaModule(xml_module.toxml(), module_id)
|
||||
smod=StudentModule(student=request.user,
|
||||
module_id=filename,
|
||||
module_id=module_id,
|
||||
state=problem.get_state())
|
||||
smod.save()
|
||||
elif len(s) == 1:
|
||||
# If so, render it
|
||||
problem=capa_problem.LoncapaProblem(settings.DATA_DIR+filename+'.xml',
|
||||
id=filename,
|
||||
state=s[0].state)
|
||||
problem=capa_module.LoncapaModule(xml_module.toxml(),
|
||||
module_id,
|
||||
state=s[0].state)
|
||||
else:
|
||||
raise Exception("Database is inconsistent (1).")
|
||||
|
||||
return problem.get_html()
|
||||
|
||||
def reset_problem(request):
|
||||
s = StudentModule.objects.filter(student=request.user, module_id=request.GET['id'])
|
||||
return {'content':problem.get_html()}
|
||||
|
||||
def modx_dispatch(request, dispatch=None, id=None):
|
||||
s = StudentModule.objects.filter(student=request.user, module_id=id)
|
||||
if len(s) == 0:
|
||||
raise Http404
|
||||
|
||||
if dispatch=='problem_check':
|
||||
return check_problem(request)
|
||||
elif dispatch=='problem_reset':
|
||||
return reset_problem(request,id)
|
||||
else:
|
||||
print "AAA"
|
||||
raise Http404
|
||||
|
||||
|
||||
def reset_problem(request,id):
|
||||
s = StudentModule.objects.filter(student=request.user, module_id=id)
|
||||
s[0].delete()
|
||||
return HttpResponse(json.dumps({}), mimetype="application/json")
|
||||
|
||||
@@ -194,32 +190,11 @@ def check_problem(request):
|
||||
|
||||
return HttpResponse(js, mimetype="application/json")
|
||||
|
||||
def problem_module(request, module):
|
||||
filename=module.getAttribute('filename')
|
||||
content={'name':module.getAttribute('name'),
|
||||
'html':render_problem(request, filename)}
|
||||
return {'content':render_to_string('problem.html', {'problem':content, 'id':filename})}
|
||||
|
||||
def homework_module(request, module):
|
||||
content={'name':module.getAttribute('name'),
|
||||
'problems':[]}
|
||||
filename=module.getAttribute('filename')
|
||||
dom=parse(settings.DATA_DIR+filename)
|
||||
homework=dom.getElementsByTagName('homework')[0]
|
||||
for e in homework.childNodes:
|
||||
if e.nodeType==1:
|
||||
problem={'name':e.getAttribute('name'),
|
||||
'html':render_problem(request, e.getAttribute('filename'))}
|
||||
content['problems'].append(problem)
|
||||
|
||||
return {'content':render_to_string('homework.html', {'homework':content})}
|
||||
|
||||
module_types={'video':video_module,
|
||||
'html':html_module,
|
||||
'tab':tab_module,
|
||||
'vertical':vertical_module,
|
||||
'homework':homework_module,
|
||||
'problem':problem_module}
|
||||
'problem':render_x_module}
|
||||
#'lab':lab_module,
|
||||
|
||||
def render_module(request, module):
|
||||
|
||||
@@ -3,6 +3,14 @@ class XModule:
|
||||
Initialized on access with __init__, first time with state=None, and
|
||||
then with state
|
||||
'''
|
||||
def get_xml_tags():
|
||||
''' Tags in the courseware file guaranteed to correspond to the module '''
|
||||
return []
|
||||
|
||||
def get_id_attribute():
|
||||
''' An attribute in the XML scheme that is guaranteed unique. '''
|
||||
return "name"
|
||||
|
||||
def get_state(self):
|
||||
return ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user