Commit 9e18b261 by Piotr Mitros

Refactoring into module, part 1

parent cc1de22e
...@@ -4,26 +4,48 @@ ...@@ -4,26 +4,48 @@
import random, numpy, math, scipy, sys, StringIO, os, struct, json import random, numpy, math, scipy, sys, StringIO, os, struct, json
from x_module import XModule from x_module import XModule
from capa_problem import LoncapaProblem
from xml.dom.minidom import parse, parseString 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): def get_state(self):
print "got"
return self.lcp.get_state()
def get_score(self): def get_score(self):
return self.lcp.get_score()
def max_score(self): def max_score(self):
return len(lcp.questions)
def get_html(self): def get_html(self):
inner_html=self.lcp.get_html()
content={'name':self.name,
'html':inner_html}
return render_to_string('problem.html',
{'problem':content, 'id':self.filename})
def handle_ajax(self, json):
def __init__(self, filename, id=None, state=None):
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)
if __name__=='__main__': # Temporary
p=LoncapaProblem('<problem name="Problem 1: Resistive Divider" filename="resistor" />')
print p.getHtml() def check_problem(self, get):
print p.getContext() pass
print p.getSeed()
# Chef and puppot
...@@ -26,16 +26,10 @@ class LoncapaProblem(): ...@@ -26,16 +26,10 @@ class LoncapaProblem():
return {'score':correct, return {'score':correct,
'total':len(self.questions)} 'total':len(self.questions)}
def max_score(self):
pass
def get_html(self): def get_html(self):
''' Return the HTML of the question ''' ''' Return the HTML of the question '''
return self.text return self.text
def handle_ajax(self, json):
pass
def __init__(self, filename, id=None, state=None): def __init__(self, filename, id=None, state=None):
''' Create a new problem of the type defined in filename. ''' Create a new problem of the type defined in filename.
By default, this will generate a random problem. Passing By default, this will generate a random problem. Passing
...@@ -71,7 +65,7 @@ class LoncapaProblem(): ...@@ -71,7 +65,7 @@ class LoncapaProblem():
ot=False ## Are we in an outtext context? ot=False ## Are we in an outtext context?
for e in dom.childNodes: 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 exec e.childNodes[0].data in g,self.context
if e.localName=='endouttext': if e.localName=='endouttext':
ot=False ot=False
...@@ -85,7 +79,7 @@ class LoncapaProblem(): ...@@ -85,7 +79,7 @@ class LoncapaProblem():
self.text=buf.getvalue() self.text=buf.getvalue()
self.text=self.contextualize_text(self.text) self.text=self.contextualize_text(self.text)
self.filename=filename
text="" text=""
context={} # Execution context from loncapa/python context={} # Execution context from loncapa/python
......
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): ...@@ -44,10 +44,13 @@ class StudentModule(models.Model):
state = models.TextField(null=True, blank=True) state = models.TextField(null=True, blank=True)
grade = models.FloatField(null=True, blank=True) grade = models.FloatField(null=True, blank=True)
student = models.ForeignKey(User) student = models.ForeignKey(User)
MODULE_TYPES = (('hw','homework'),) MODULE_TYPES = (('problem','problem'),)
module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='hw') module_type = models.CharField(max_length=32, choices=MODULE_TYPES, default='problem')
module_id = models.CharField(max_length=255) # Filename module_id = models.CharField(max_length=255) # Filename for homeworks, etc.
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True) modified = models.DateTimeField(auto_now=True)
class Meta: 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 ...@@ -12,9 +12,11 @@ from django.shortcuts import redirect
import StringIO import StringIO
from django.http import Http404
import urllib import urllib
import capa_problem import capa_module, capa_problem
from models import StudentModule from models import StudentModule
...@@ -22,6 +24,8 @@ import urllib ...@@ -22,6 +24,8 @@ import urllib
from django.conf import settings from django.conf import settings
from content_parser import *
template_imports={'urllib':urllib} template_imports={'urllib':urllib}
def profile(request): def profile(request):
...@@ -49,9 +53,7 @@ def profile(request): ...@@ -49,9 +53,7 @@ def profile(request):
correct=response.grade correct=response.grade
else: else:
correct=0 correct=0
# CRITICAL TODO: Benchmark, and probably cache. We shouldn't recalculate this total=capa_module.LoncapaModule(p, id=id).max_score()
# every time. By modularity, this also belongs inside LoncapaProblem.
total=len(capa_problem.LoncapaProblem(settings.DATA_DIR+id+'.xml', id=id).questions)
scores.append((int(correct),total)) scores.append((int(correct),total))
score={'course':course.getAttribute('name'), score={'course':course.getAttribute('name'),
'section':s.getAttribute("name"), 'section':s.getAttribute("name"),
...@@ -71,27 +73,6 @@ def profile(request): ...@@ -71,27 +73,6 @@ def profile(request):
} }
return render_to_response('profile.html', context) 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): def render_accordion(request,course,chapter,section):
''' Draws accordion. Takes current position in accordion as ''' Draws accordion. Takes current position in accordion as
parameter. Returns (initialization_javascript, content)''' parameter. Returns (initialization_javascript, content)'''
...@@ -138,28 +119,43 @@ def vertical_module(request, module): ...@@ -138,28 +119,43 @@ def vertical_module(request, module):
return {'js':js, return {'js':js,
'content':render_to_string('vert_module.html',{'items':contents})} '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 # 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 len(s) == 0:
# If not, create one, and return it # If not, create one, and save it
problem=capa_problem.LoncapaProblem(settings.DATA_DIR+filename+'.xml', id=filename) problem=capa_module.LoncapaModule(xml_module.toxml(), module_id)
smod=StudentModule(student=request.user, smod=StudentModule(student=request.user,
module_id=filename, module_id=module_id,
state=problem.get_state()) state=problem.get_state())
smod.save() smod.save()
elif len(s) == 1: elif len(s) == 1:
# If so, render it # If so, render it
problem=capa_problem.LoncapaProblem(settings.DATA_DIR+filename+'.xml', problem=capa_module.LoncapaModule(xml_module.toxml(),
id=filename, module_id,
state=s[0].state) state=s[0].state)
else: else:
raise Exception("Database is inconsistent (1).") raise Exception("Database is inconsistent (1).")
return problem.get_html()
def reset_problem(request): return {'content':problem.get_html()}
s = StudentModule.objects.filter(student=request.user, module_id=request.GET['id'])
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() s[0].delete()
return HttpResponse(json.dumps({}), mimetype="application/json") return HttpResponse(json.dumps({}), mimetype="application/json")
...@@ -194,32 +190,11 @@ def check_problem(request): ...@@ -194,32 +190,11 @@ def check_problem(request):
return HttpResponse(js, mimetype="application/json") 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, module_types={'video':video_module,
'html':html_module, 'html':html_module,
'tab':tab_module, 'tab':tab_module,
'vertical':vertical_module, 'vertical':vertical_module,
'homework':homework_module, 'problem':render_x_module}
'problem':problem_module}
#'lab':lab_module, #'lab':lab_module,
def render_module(request, module): def render_module(request, module):
......
...@@ -3,6 +3,14 @@ class XModule: ...@@ -3,6 +3,14 @@ class XModule:
Initialized on access with __init__, first time with state=None, and Initialized on access with __init__, first time with state=None, and
then with state 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): def get_state(self):
return "" return ""
......
...@@ -9,8 +9,8 @@ urlpatterns = patterns('', ...@@ -9,8 +9,8 @@ urlpatterns = patterns('',
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index'), url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$', 'courseware.views.index'),
url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index'), url(r'^courseware/(?P<course>[^/]*)/(?P<chapter>[^/]*)/$', 'courseware.views.index'),
url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index'), url(r'^courseware/(?P<course>[^/]*)/$', 'courseware.views.index'),
url(r'^courseware/problem_check$', 'courseware.views.check_problem'), # url(r'^courseware/modx/(?P<id>[^/]*)/problem_check$', 'courseware.views.check_problem'),
url(r'^courseware/problem_reset$', 'courseware.views.reset_problem'), url(r'^courseware/modx/(?P<id>[^/]*)/(?P<dispatch>[^/]*)$', 'courseware.views.modx_dispatch'), #reset_problem'),
url(r'^courseware/$', 'courseware.views.index'), url(r'^courseware/$', 'courseware.views.index'),
url(r'^profile$', 'courseware.views.profile'), url(r'^profile$', 'courseware.views.profile'),
# url(r'^admin/', include('django.contrib.admin.urls')), # url(r'^admin/', include('django.contrib.admin.urls')),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment