Commit 07454b82 by Piotr Mitros

Factored out a couple of modules

--HG--
rename : courseware/static/schematic.js => courseware/static/js/schematic.js
parent e31356b1
...@@ -5,13 +5,13 @@ import uuid ...@@ -5,13 +5,13 @@ import uuid
class UserProfile(models.Model): class UserProfile(models.Model):
## CRITICAL TODO/SECURITY ## CRITICAL TODO/SECURITY
# Sanitize all fields. # Sanitize all fields.
# This is not visible to other users, but could introduce holes # This is not visible to other users, but could introduce holes later
# later
user = models.ForeignKey(User, unique=True, db_index=True) user = models.ForeignKey(User, unique=True, db_index=True)
name = models.TextField(blank=True) name = models.TextField(blank=True)
language = models.TextField(blank=True) language = models.TextField(blank=True)
location = models.TextField(blank=True) location = models.TextField(blank=True)
meta = models.TextField(blank=True) # JSON dictionary for future expansion meta = models.TextField(blank=True) # JSON dictionary for future expansion
courseware = models.TextField(blank=True)
class Registration(models.Model): class Registration(models.Model):
''' Allows us to wait for e-mail before user is registered. A ''' Allows us to wait for e-mail before user is registered. A
......
...@@ -6,6 +6,10 @@ from x_module import XModule ...@@ -6,6 +6,10 @@ from x_module import XModule
from capa_problem import LoncapaProblem from capa_problem import LoncapaProblem
import dateutil
import datetime
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
## TODO: Abstract out from Django ## TODO: Abstract out from Django
...@@ -18,8 +22,13 @@ class LoncapaModule(XModule): ...@@ -18,8 +22,13 @@ class LoncapaModule(XModule):
prupose now. We can e.g .destroy and create the capa_problem on a prupose now. We can e.g .destroy and create the capa_problem on a
reset. reset.
''' '''
xml_tags=["problem"] xml_tags = ["problem"]
id_attribute="filename" id_attribute = "filename"
attempts = None
max_attempts = None
due_date = None
def get_state(self): def get_state(self):
return self.lcp.get_state() return self.lcp.get_state()
...@@ -66,18 +75,33 @@ class LoncapaModule(XModule): ...@@ -66,18 +75,33 @@ class LoncapaModule(XModule):
XModule.__init__(self, xml, item_id, ajax_url, track_url, state) XModule.__init__(self, xml, item_id, ajax_url, track_url, state)
dom=parseString(xml) dom=parseString(xml)
node=dom.childNodes[0] node=dom.childNodes[0]
self.due_date=node.getAttribute("due")
if len(self.due_date)>0:
self.due_date=dateutil.parser.parse(self.due_date)
else:
self.due_date=None
self.max_attempts=node.getAttribute("attempts")
if len(self.max_attempts)>0:
self.max_attempts=int(self.max_attempts)
else:
self.max_attempts=None
self.filename=node.getAttribute("filename") self.filename=node.getAttribute("filename")
filename=settings.DATA_DIR+self.filename+".xml" filename=settings.DATA_DIR+self.filename+".xml"
self.name=node.getAttribute("name") self.name=node.getAttribute("name")
self.lcp=LoncapaProblem(filename, self.item_id, state) self.lcp=LoncapaProblem(filename, self.item_id, state)
def handle_ajax(self, dispatch, get): def handle_ajax(self, dispatch, get):
if dispatch=='problem_check': if dispatch=='problem_get':
response = self.get_problem(get)
elif False: #self.due_date >
return json.dumps({"error":"Past due date"})
elif dispatch=='problem_check':
response = self.check_problem(get) response = self.check_problem(get)
elif dispatch=='problem_reset': elif dispatch=='problem_reset':
response = self.reset_problem(get) response = self.reset_problem(get)
elif dispatch=='problem_get':
response = self.get_problem(get)
else: else:
return "Error" return "Error"
return response return response
......
import random, numpy, math, scipy, sys, StringIO, os, struct, json import random, numpy, math, scipy, sys, StringIO, os, struct, json
from dateutil import parser
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
...@@ -198,6 +199,7 @@ class LoncapaProblem(): ...@@ -198,6 +199,7 @@ class LoncapaProblem():
return html return html
def grade_fr(self, question, answer): def grade_fr(self, question, answer):
print question, answer
correct = True correct = True
for i in range(question['samples_count']): for i in range(question['samples_count']):
instructor_variables = strip_dict(dict(self.context)) instructor_variables = strip_dict(dict(self.context))
...@@ -208,6 +210,9 @@ class LoncapaProblem(): ...@@ -208,6 +210,9 @@ class LoncapaProblem():
student_variables[str(var)] = value student_variables[str(var)] = value
instructor_result = evaluator(instructor_variables,{},str(question['answer'])) instructor_result = evaluator(instructor_variables,{},str(question['answer']))
student_result = evaluator(student_variables,{},str(answer)) student_result = evaluator(student_variables,{},str(answer))
print student_result, instructor_result
if math.isnan(student_result) or math.isinf(student_result):
return "incorrect"
if abs( student_result - instructor_result ) > question['tolerance']: if abs( student_result - instructor_result ) > question['tolerance']:
return "incorrect" return "incorrect"
......
from x_module import XModule
from xml.dom.minidom import parse, parseString
import json
## TODO: Abstract out from Django
from django.conf import settings
from djangomako.shortcuts import render_to_response, render_to_string
class HtmlModule(XModule):
id_attribute = 'filename'
def get_state(self):
return json.dumps({ })
def get_xml_tags():
return "html"
def get_html(self):
print "XX",self.item_id
return render_to_string(self.item_id, {'id': self.item_id})
def __init__(self, xml, item_id, ajax_url=None, track_url=None, state=None):
print "item id" , item_id
XModule.__init__(self, xml, item_id, ajax_url, track_url, state)
# template_source=module.getAttribute('filename')
# return {'content':render_to_string(template_source, {})}
# print state
# if state!=None and "time" not in json.loads(state):
# self.video_time = 0
from django.http import HttpResponse
from django.template import Context, loader
from djangomako.shortcuts import render_to_response, render_to_string
from xml.dom.minidom import parse, parseString
import json, os, sys
from django.core.context_processors import csrf
from django.template import Context
from django.contrib.auth.models import User
from auth.models import UserProfile
from django.shortcuts import redirect
import StringIO
from django.http import Http404
import urllib
import capa_module
import video_module
import html_module
from models import StudentModule
import urllib
from django.conf import settings
import content_parser
import uuid
#def html_module(request, module):
# ''' Show basic text
# '''
# template_source=module.getAttribute('filename')
# return {'content':render_to_string(template_source, {})}
def vertical_module(request, module):
''' Layout module which lays out content vertically.
'''
contents=[(e.getAttribute("name"),render_module(request, e)) \
for e in module.childNodes \
if e.nodeType==1]
js="".join([e[1]['init_js'] for e in contents if 'init_js' in e[1]])
return {'init_js':js,
"destroy_js":"",
'content':render_to_string('vert_module.html',{'items':contents})}
def seq_module(request, module):
''' Layout module which lays out content in a temporal sequence
'''
def j(m):
# jsonify contents so it can be embedded in a js array
# We also need to split </script> tags so they don't break
# mid-string
if 'init_js' not in m: m['init_js']=""
content=json.dumps(m['content'])
content=content.replace('</script>', '<"+"/script>')
return {'content':content,
"destroy_js":"",
'init_js':m['init_js']}
contents=[(e.getAttribute("name"),j(render_module(request, e))) \
for e in module.childNodes \
if e.nodeType==1]
js="".join([e[1]['init_js'] for e in contents if 'init_js' in e[1]])
iid=uuid.uuid1().hex
params={'items':contents,
'id':"seq"}
print module.nodeName
if module.nodeName == 'sequential':
return {'init_js':js+render_to_string('seq_module.js',params),
"destroy_js":"",
'content':render_to_string('seq_module.html',params)}
if module.nodeName == 'tab':
return {'init_js':js+render_to_string('tab_module.js',params),
"destroy_js":"",
'content':render_to_string('tab_module.html',params)}
modx_modules={'problem':capa_module.LoncapaModule,
'video':video_module.VideoModule,
'html':html_module.HtmlModule}
def render_x_module(request, xml_module):
''' Generic module for extensions. This renders to HTML. '''
# Check if problem has an instance in DB
module_type=xml_module.nodeName
module_class=modx_modules[module_type]
print "mida",module_class.id_attribute
module_id=xml_module.getAttribute(module_class.id_attribute)
print "mid",module_id
# Grab state from database
s = StudentModule.objects.filter(student=request.user,
module_id=module_id,
module_type = module_type)
if len(s) == 0: # If nothing in the database...
state=None
else:
smod = s[0]
state = smod.state
# Create a new instance
ajax_url = '/modx/'+module_type+'/'+module_id+'/'
instance=module_class(xml_module.toxml(),
module_id,
ajax_url=ajax_url,
state=state)
# If instance wasn't already in the database, create it
if len(s) == 0:
smod=StudentModule(student=request.user,
module_type = module_type,
module_id=module_id,
state=instance.get_state(),
xml=instance.xml)
# Grab content
content = {'content':instance.get_html(),
"destroy_js":instance.get_destroy_js(),
'init_js':instance.get_init_js()}
smod.save() # This may be optional (at least in the case of no instance in the dB)
return content
def modx_dispatch(request, module=None, dispatch=None, id=None):
''' Generic module for extensions. '''
s = StudentModule.objects.filter(module_type=module, student=request.user, module_id=id)
if len(s) == 0:
raise Http404
s=s[0]
dispatch=dispatch.split('?')[0]
ajax_url = '/modx/'+module+'/'+id+'/'
instance=modx_modules[module](s.xml, s.module_id, ajax_url=ajax_url, state=s.state)
html=instance.handle_ajax(dispatch, request.GET)
s.state=instance.get_state()
s.grade=instance.get_score()['score']
s.save()
return HttpResponse(html)
module_types={'video':render_x_module,
'html':render_x_module,
'tab':seq_module,
'vertical':vertical_module,
'sequential':seq_module,
'problem':render_x_module,
}
#'lab':lab_module,
def render_module(request, module):
''' Generic dispatch for internal modules. '''
if module==None:
return {"content":""}
if str(module.localName) in module_types:
return module_types[module.localName](request, module)
raise Http404
def profile(request):
''' User profile. Show username, location, etc, as well as grades .
We need to allow the user to change some of these settings .'''
if not request.user.is_authenticated():
return redirect('/')
dom=parse(settings.DATA_DIR+'course.xml')
hw=[]
course = dom.getElementsByTagName('course')[0]
chapters = course.getElementsByTagName('chapter')
responses=StudentModule.objects.filter(student=request.user)
for c in chapters:
for s in c.getElementsByTagName('section'):
problems=s.getElementsByTagName('problem')
scores=[]
if len(problems)>0:
for p in problems:
id = p.getAttribute('filename')
correct = 0
for response in responses:
if response.module_id == id:
if response.grade!=None:
correct=response.grade
else:
correct=0
total=capa_module.LoncapaModule(p.toxml(), "id").max_score() # TODO: Add state. Not useful now, but maybe someday problems will have randomized max scores?
scores.append((int(correct),total))
score={'course':course.getAttribute('name'),
'section':s.getAttribute("name"),
'chapter':c.getAttribute("name"),
'scores':scores,
}
hw.append(score)
user_info=UserProfile.objects.get(user=request.user)
context={'name':user_info.name,
'username':request.user.username,
'location':user_info.location,
'language':user_info.language,
'email':request.user.email,
'homeworks':hw,
'csrf':csrf(request)['csrf_token']
}
return render_to_response('profile.html', context)
# For calculator:
# http://pyparsing.wikispaces.com/file/view/fourFn.py
from x_module import XModule from x_module import XModule
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
...@@ -12,10 +9,6 @@ from django.conf import settings ...@@ -12,10 +9,6 @@ from django.conf import settings
from djangomako.shortcuts import render_to_response, render_to_string from djangomako.shortcuts import render_to_response, render_to_string
class VideoModule(XModule): class VideoModule(XModule):
''' Implements a generic learning module.
Initialized on access with __init__, first time with state=None, and
then with state
'''
id_attribute = 'youtube' id_attribute = 'youtube'
video_time = 0 video_time = 0
...@@ -31,11 +24,7 @@ class VideoModule(XModule): ...@@ -31,11 +24,7 @@ class VideoModule(XModule):
def get_xml_tags(): def get_xml_tags():
''' Tags in the courseware file guaranteed to correspond to the module ''' ''' Tags in the courseware file guaranteed to correspond to the module '''
return "video1" return "video"
def get_id_attribute():
''' An attribute in the XML scheme that is guaranteed unique. '''
return "youtube"
def get_html(self): def get_html(self):
return render_to_string('video.html',{'id':self.item_id, return render_to_string('video.html',{'id':self.item_id,
......
...@@ -29,6 +29,8 @@ import content_parser ...@@ -29,6 +29,8 @@ import content_parser
import uuid import uuid
from module_render import *
template_imports={'urllib':urllib} template_imports={'urllib':urllib}
def profile(request): def profile(request):
...@@ -98,131 +100,6 @@ def render_accordion(request,course,chapter,section): ...@@ -98,131 +100,6 @@ def render_accordion(request,course,chapter,section):
return {'init_js':render_to_string('accordion_init.js',context), return {'init_js':render_to_string('accordion_init.js',context),
'content':render_to_string('accordion.html',context)} 'content':render_to_string('accordion.html',context)}
def html_module(request, module):
''' Show basic text
'''
template_source=module.getAttribute('filename')
return {'content':render_to_string(template_source, {})}
def vertical_module(request, module):
''' Layout module which lays out content vertically.
'''
contents=[(e.getAttribute("name"),render_module(request, e)) \
for e in module.childNodes \
if e.nodeType==1]
js="".join([e[1]['init_js'] for e in contents if 'init_js' in e[1]])
return {'init_js':js,
'content':render_to_string('vert_module.html',{'items':contents})}
def seq_module(request, module):
''' Layout module which lays out content in a temporal sequence
'''
def j(m):
# jsonify contents so it can be embedded in a js array
# We also need to split </script> tags so they don't break
# mid-string
if 'init_js' not in m: m['init_js']=""
content=json.dumps(m['content'])
content=content.replace('</script>', '<"+"/script>')
return {'content':content, 'init_js':m['init_js']}
contents=[(e.getAttribute("name"),j(render_module(request, e))) \
for e in module.childNodes \
if e.nodeType==1]
js="".join([e[1]['init_js'] for e in contents if 'init_js' in e[1]])
iid=uuid.uuid1().hex
params={'items':contents,
'id':"seq"}
print module.nodeName
if module.nodeName == 'sequential':
return {'init_js':js+render_to_string('seq_module.js',params),
'content':render_to_string('seq_module.html',params)}
if module.nodeName == 'tab':
return {'init_js':js+render_to_string('tab_module.js',params),
'content':render_to_string('tab_module.html',params)}
modx_modules={'problem':capa_module.LoncapaModule, 'video':video_module.VideoModule}
def render_x_module(request, xml_module):
''' Generic module for extensions. This renders to HTML. '''
# Check if problem has an instance in DB
module_type=xml_module.nodeName
module_class=modx_modules[module_type]
module_id=xml_module.getAttribute(module_class.id_attribute)
# Grab state from database
s = StudentModule.objects.filter(student=request.user,
module_id=module_id,
module_type = module_type)
if len(s) == 0: # If nothing in the database...
state=None
else:
smod = s[0]
state = smod.state
# Create a new instance
ajax_url = '/modx/'+module_type+'/'+module_id+'/'
instance=module_class(xml_module.toxml(),
module_id,
ajax_url=ajax_url,
state=state)
# If instance wasn't already in the database, create it
if len(s) == 0:
smod=StudentModule(student=request.user,
module_type = module_type,
module_id=module_id,
state=instance.get_state(),
xml=instance.xml)
# Grab content
content = {'content':instance.get_html(),
'init_js':instance.get_init_js()}
smod.save() # This may be optional (at least in the case of no instance in the dB)
return content
def modx_dispatch(request, module=None, dispatch=None, id=None):
''' Generic module for extensions. '''
s = StudentModule.objects.filter(module_type=module, student=request.user, module_id=id)
if len(s) == 0:
raise Http404
s=s[0]
dispatch=dispatch.split('?')[0]
ajax_url = '/modx/'+module+'/'+id+'/'
instance=modx_modules[module](s.xml, s.module_id, ajax_url=ajax_url, state=s.state)
html=instance.handle_ajax(dispatch, request.GET)
s.state=instance.get_state()
s.grade=instance.get_score()['score']
s.save()
return HttpResponse(html)
module_types={'video':render_x_module,
'html':html_module,
'tab':seq_module,
'vertical':vertical_module,
'sequential':seq_module,
'problem':render_x_module,
}
#'lab':lab_module,
def render_module(request, module):
''' Generic dispatch for internal modules. '''
if module==None:
return {"content":""}
if str(module.localName) in module_types:
return module_types[module.localName](request, module)
return {"content":""}
def index(request, course="6.002 Spring 2012", chapter="Using the System", section="Hints"): def index(request, course="6.002 Spring 2012", chapter="Using the System", section="Hints"):
''' Displays courseware accordion, and any associated content. ''' Displays courseware accordion, and any associated content.
''' '''
......
...@@ -3,14 +3,12 @@ class XModule: ...@@ -3,14 +3,12 @@ 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
''' '''
id_attribute='name' # An attribute guaranteed to be unique
def get_xml_tags(): def get_xml_tags():
''' Tags in the courseware file guaranteed to correspond to the module ''' ''' Tags in the courseware file guaranteed to correspond to the module '''
return [] 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 ""
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
from djangomako.shortcuts import render_to_response, render_to_string from djangomako.shortcuts import render_to_response, render_to_string
from django.shortcuts import redirect from django.shortcuts import redirect
valid_templates=['index.html', 'staff.html', 'info.html'] valid_templates=['index.html', 'staff.html', 'info.html', 'credits.html']
def index(request, template): def index(request, template):
if template in valid_templates: if template in valid_templates:
......
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