Commit 9b90068e by ichuang

Merge branch 'stable-edx4edx' of github.com:MITx/mitx

Conflicts:
	common/lib/xmodule/seq_module.py
	common/lib/xmodule/xmodule/capa_module.py
	lms/djangoapps/courseware/module_render.py
	lms/djangoapps/courseware/views.py
	lms/djangoapps/multicourse/multicourse_settings.py
parents 9801ce5d 74e01bb0
GEM
remote: http://rubygems.org/
specs:
bourbon (1.3.6)
sass (>= 3.1)
rake (0.9.2.2)
sass (3.1.15)
PLATFORMS
ruby
DEPENDENCIES
bourbon (~> 1.3.6)
rake
sass (= 3.1.15)
#! /bin/bash
cd $(dirname $0) && django-admin.py collectstatic --noinput --settings=envs.aws --pythonpath=.
...@@ -251,7 +251,7 @@ class LoncapaProblem(object): ...@@ -251,7 +251,7 @@ class LoncapaProblem(object):
if file is not None: if file is not None:
try: try:
ifp = self.system.filestore.open(file) # open using I4xSystem OSFS filestore ifp = self.system.filestore.open(file) # open using I4xSystem OSFS filestore
except Exception,err: except Exception as err:
log.error('Error %s in problem xml include: %s' % (err,etree.tostring(inc,pretty_print=True))) log.error('Error %s in problem xml include: %s' % (err,etree.tostring(inc,pretty_print=True)))
log.error('Cannot find file %s in %s' % (file,self.system.filestore)) log.error('Cannot find file %s in %s' % (file,self.system.filestore))
if not self.system.get('DEBUG'): # if debugging, don't fail - just log error if not self.system.get('DEBUG'): # if debugging, don't fail - just log error
...@@ -259,7 +259,7 @@ class LoncapaProblem(object): ...@@ -259,7 +259,7 @@ class LoncapaProblem(object):
else: continue else: continue
try: try:
incxml = etree.XML(ifp.read()) # read in and convert to XML incxml = etree.XML(ifp.read()) # read in and convert to XML
except Exception,err: except Exception as err:
log.error('Error %s in problem xml include: %s' % (err,etree.tostring(inc,pretty_print=True))) log.error('Error %s in problem xml include: %s' % (err,etree.tostring(inc,pretty_print=True)))
log.error('Cannot parse XML in %s' % (file)) log.error('Cannot parse XML in %s' % (file))
if not self.system.get('DEBUG'): # if debugging, don't fail - just log error if not self.system.get('DEBUG'): # if debugging, don't fail - just log error
...@@ -283,6 +283,7 @@ class LoncapaProblem(object): ...@@ -283,6 +283,7 @@ class LoncapaProblem(object):
context.update(global_context) # initialize context to have stuff in global_context context.update(global_context) # initialize context to have stuff in global_context
context['__builtins__'] = globals()['__builtins__'] # put globals there also context['__builtins__'] = globals()['__builtins__'] # put globals there also
context['the_lcp'] = self # pass instance of LoncapaProblem in context['the_lcp'] = self # pass instance of LoncapaProblem in
context['script_code'] = ''
for script in tree.findall('.//script'): for script in tree.findall('.//script'):
stype = script.get('type') stype = script.get('type')
...@@ -295,10 +296,12 @@ class LoncapaProblem(object): ...@@ -295,10 +296,12 @@ class LoncapaProblem(object):
code = script.text code = script.text
XMLESC = {"'": "'", """: '"'} XMLESC = {"'": "'", """: '"'}
code = unescape(code, XMLESC) code = unescape(code, XMLESC)
context['script_code'] += code # store code source in context
try: try:
exec code in context, context # use "context" for global context; thus defs in code are global within code exec code in context, context # use "context" for global context; thus defs in code are global within code
except Exception: except Exception:
log.exception("Error while execing code: " + code) log.exception("Error while execing script code: " + code)
raise responsetypes.LoncapaProblemError("Error while executing script code")
return context return context
def _extract_html(self, problemtree): # private def _extract_html(self, problemtree): # private
...@@ -311,6 +314,10 @@ class LoncapaProblem(object): ...@@ -311,6 +314,10 @@ class LoncapaProblem(object):
Used by get_html. Used by get_html.
''' '''
if problemtree.tag=='script' and problemtree.get('type') and 'javascript' in problemtree.get('type'):
# leave javascript intact.
return problemtree
if problemtree.tag in html_problem_semantics: if problemtree.tag in html_problem_semantics:
return return
......
...@@ -22,10 +22,14 @@ Each input type takes the xml tree as 'element', the previous answer as 'value', ...@@ -22,10 +22,14 @@ Each input type takes the xml tree as 'element', the previous answer as 'value',
# status is currently the answer for the problem ID for the input element, # status is currently the answer for the problem ID for the input element,
# but it will turn into a dict containing both the answer and any associated message for the problem ID for the input element. # but it will turn into a dict containing both the answer and any associated message for the problem ID for the input element.
import logging
import re import re
import shlex # for splitting quoted strings import shlex # for splitting quoted strings
from lxml import etree from lxml import etree
import xml.sax.saxutils as saxutils
log = logging.getLogger('mitx.' + __name__)
def get_input_xml_tags(): def get_input_xml_tags():
''' Eventually, this will be for all registered input types ''' ''' Eventually, this will be for all registered input types '''
...@@ -121,7 +125,7 @@ def optioninput(element, value, status, render_template, msg=''): ...@@ -121,7 +125,7 @@ def optioninput(element, value, status, render_template, msg=''):
eid=element.get('id') eid=element.get('id')
options = element.get('options') options = element.get('options')
if not options: if not options:
raise Exception,"[courseware.capa.inputtypes.optioninput] Missing options specification in " + etree.tostring(element) raise Exception("[courseware.capa.inputtypes.optioninput] Missing options specification in " + etree.tostring(element))
oset = shlex.shlex(options[1:-1]) oset = shlex.shlex(options[1:-1])
oset.quotes = "'" oset.quotes = "'"
oset.whitespace = "," oset.whitespace = ","
...@@ -159,10 +163,11 @@ def choicegroup(element, value, status, render_template, msg=''): ...@@ -159,10 +163,11 @@ def choicegroup(element, value, status, render_template, msg=''):
choices={} choices={}
for choice in element: for choice in element:
if not choice.tag=='choice': if not choice.tag=='choice':
raise Exception,"[courseware.capa.inputtypes.choicegroup] Error only <choice> tags should be immediate children of a <choicegroup>, found %s instead" % choice.tag raise Exception("[courseware.capa.inputtypes.choicegroup] Error only <choice> tags should be immediate children of a <choicegroup>, found %s instead" % choice.tag)
ctext = "" ctext = ""
ctext += ''.join([etree.tostring(x) for x in choice]) # TODO: what if choice[0] has math tags in it? ctext += ''.join([etree.tostring(x) for x in choice]) # TODO: what if choice[0] has math tags in it?
ctext += choice.text # TODO: fix order? if choice.text is not None:
ctext += choice.text # TODO: fix order?
choices[choice.get("name")] = ctext choices[choice.get("name")] = ctext
context={'id':eid, 'value':value, 'state':status, 'type':type, 'choices':choices} context={'id':eid, 'value':value, 'state':status, 'type':type, 'choices':choices}
html = render_template("choicegroup.html", context) html = render_template("choicegroup.html", context)
...@@ -182,9 +187,18 @@ def textline(element, value, status, render_template, msg=""): ...@@ -182,9 +187,18 @@ def textline(element, value, status, render_template, msg=""):
raise Exception(msg) raise Exception(msg)
count = int(eid.split('_')[-2])-1 # HACK count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size') size = element.get('size')
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, 'msg': msg} hidden = element.get('hidden','') # if specified, then textline is hidden and id is stored in div of name given by hidden
escapedict = {'"': '&quot;'}
value = saxutils.escape(value,escapedict) # otherwise, answers with quotes in them crashes the system!
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, 'msg': msg, 'hidden': hidden}
html = render_template("textinput.html", context) html = render_template("textinput.html", context)
return etree.XML(html) try:
xhtml = etree.XML(html)
except Exception as err:
if True: # TODO needs to be self.system.DEBUG - but can't access system
log.debug('[inputtypes.textline] failed to parse XML for:\n%s' % html)
raise
return xhtml
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
...@@ -195,7 +209,6 @@ def textline_dynamath(element, value, status, render_template, msg=''): ...@@ -195,7 +209,6 @@ def textline_dynamath(element, value, status, render_template, msg=''):
''' '''
# TODO: Make a wrapper for <formulainput> # TODO: Make a wrapper for <formulainput>
# TODO: Make an AJAX loop to confirm equation is okay in real-time as user types # TODO: Make an AJAX loop to confirm equation is okay in real-time as user types
## TODO: Code should follow PEP8 (4 spaces per indentation level)
''' '''
textline is used for simple one-line inputs, like formularesponse and symbolicresponse. textline is used for simple one-line inputs, like formularesponse and symbolicresponse.
uses a <span id=display_eid>`{::}`</span> uses a <span id=display_eid>`{::}`</span>
...@@ -204,8 +217,9 @@ def textline_dynamath(element, value, status, render_template, msg=''): ...@@ -204,8 +217,9 @@ def textline_dynamath(element, value, status, render_template, msg=''):
eid=element.get('id') eid=element.get('id')
count = int(eid.split('_')[-2])-1 # HACK count = int(eid.split('_')[-2])-1 # HACK
size = element.get('size') size = element.get('size')
hidden = element.get('hidden','') # if specified, then textline is hidden and id is stored in div of name given by hidden
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size,
'msg':msg, 'msg':msg, 'hidden' : hidden,
} }
html = render_template("textinput_dynamath.html", context) html = render_template("textinput_dynamath.html", context)
return etree.XML(html) return etree.XML(html)
...@@ -225,14 +239,24 @@ def textbox(element, value, status, render_template, msg=''): ...@@ -225,14 +239,24 @@ def textbox(element, value, status, render_template, msg=''):
rows = element.get('rows') or '30' rows = element.get('rows') or '30'
cols = element.get('cols') or '80' cols = element.get('cols') or '80'
mode = element.get('mode') or 'python' # mode for CodeMirror, eg "python" or "xml" mode = element.get('mode') or 'python' # mode for CodeMirror, eg "python" or "xml"
hidden = element.get('hidden','') # if specified, then textline is hidden and id is stored in div of name given by hidden
linenumbers = element.get('linenumbers') # for CodeMirror linenumbers = element.get('linenumbers') # for CodeMirror
if not value: value = element.text # if no student input yet, then use the default input given by the problem if not value: value = element.text # if no student input yet, then use the default input given by the problem
context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, 'msg':msg, context = {'id':eid, 'value':value, 'state':status, 'count':count, 'size': size, 'msg':msg,
'mode':mode, 'linenumbers':linenumbers, 'mode':mode, 'linenumbers':linenumbers,
'rows':rows, 'cols':cols, 'rows':rows, 'cols':cols,
'hidden' : hidden,
} }
html = render_template("textbox.html", context) html = render_template("textbox.html", context)
return etree.XML(html) try:
xhtml = etree.XML(html)
except Exception as err:
newmsg = 'error %s in rendering message' % (str(err).replace('<','&lt;'))
newmsg += '<br/>Original message: %s' % msg.replace('<','&lt;')
context['msg'] = newmsg
html = render_template("textbox.html", context)
xhtml = etree.XML(html)
return xhtml
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@register_render_function @register_render_function
...@@ -288,8 +312,18 @@ def math(element, value, status, render_template, msg=''): ...@@ -288,8 +312,18 @@ def math(element, value, status, render_template, msg=''):
# isinline = True # isinline = True
# html = render_template("mathstring.html",{'mathstr':mathstr,'isinline':isinline,'tail':element.tail}) # html = render_template("mathstring.html",{'mathstr':mathstr,'isinline':isinline,'tail':element.tail})
html = '<html><html>%s</html><html>%s</html></html>' % (mathstr,element.tail) html = '<html><html>%s</html><html>%s</html></html>' % (mathstr,saxutils.escape(element.tail))
xhtml = etree.XML(html) try:
xhtml = etree.XML(html)
except Exception as err:
if False: # TODO needs to be self.system.DEBUG - but can't access system
msg = "<html><font color='red'><p>Error %s</p>" % str(err).replace('<','&lt;')
msg += '<p>Failed to construct math expression from <pre>%s</pre></p>' % html.replace('<','&lt;')
msg += "</font></html>"
log.error(msg)
return etree.XML(msg)
else:
raise
# xhtml.tail = element.tail # don't forget to include the tail! # xhtml.tail = element.tail # don't forget to include the tail!
return xhtml return xhtml
...@@ -338,14 +372,14 @@ def imageinput(element, value, status, render_template, msg=''): ...@@ -338,14 +372,14 @@ def imageinput(element, value, status, render_template, msg=''):
(gx,gy) = (0,0) (gx,gy) = (0,0)
context = { context = {
'id':eid, 'id': eid,
'value':value, 'value': value,
'height': height, 'height': height,
'width' : width, 'width': width,
'src':src, 'src': src,
'gx':gx, 'gx': gx,
'gy':gy, 'gy': gy,
'state' : status, # to change 'state': status, # to change
'msg': msg, # to change 'msg': msg, # to change
} }
html = render_template("imageinput.html", context) html = render_template("imageinput.html", context)
......
...@@ -193,7 +193,7 @@ class LoncapaResponse(object): ...@@ -193,7 +193,7 @@ class LoncapaResponse(object):
try: try:
self.context[hintfn](self.answer_ids, student_answers, new_cmap, old_cmap) self.context[hintfn](self.answer_ids, student_answers, new_cmap, old_cmap)
except Exception, err: except Exception as err:
msg = 'Error %s in evaluating hint function %s' % (err,hintfn) msg = 'Error %s in evaluating hint function %s' % (err,hintfn)
msg += "\nSee XML source line %s" % getattr(self.xml,'sourceline','<unavailable>') msg += "\nSee XML source line %s" % getattr(self.xml,'sourceline','<unavailable>')
raise ResponseError(msg) raise ResponseError(msg)
...@@ -556,7 +556,7 @@ def sympy_check2(): ...@@ -556,7 +556,7 @@ def sympy_check2():
idset = sorted(self.answer_ids) # ordered list of answer id's idset = sorted(self.answer_ids) # ordered list of answer id's
try: try:
submission = [student_answers[k] for k in idset] # ordered list of answers submission = [student_answers[k] for k in idset] # ordered list of answers
except Exception, err: except Exception as err:
msg = '[courseware.capa.responsetypes.customresponse] error getting student answer from %s' % student_answers msg = '[courseware.capa.responsetypes.customresponse] error getting student answer from %s' % student_answers
msg += '\n idset = %s, error = %s' % (idset,err) msg += '\n idset = %s, error = %s' % (idset,err)
log.error(msg) log.error(msg)
...@@ -567,7 +567,7 @@ def sympy_check2(): ...@@ -567,7 +567,7 @@ def sympy_check2():
# if there is only one box, and it's empty, then don't evaluate # if there is only one box, and it's empty, then don't evaluate
if len(idset)==1 and not submission[0]: if len(idset)==1 and not submission[0]:
return {idset[0]:'no_answer_entered'} return CorrectMap(idset[0],'incorrect',msg='<font color="red">No answer entered!</font>')
correct = ['unknown'] * len(idset) correct = ['unknown'] * len(idset)
messages = [''] * len(idset) messages = [''] * len(idset)
...@@ -594,7 +594,7 @@ def sympy_check2(): ...@@ -594,7 +594,7 @@ def sympy_check2():
if type(self.code)==str: if type(self.code)==str:
try: try:
exec self.code in self.context['global_context'], self.context exec self.code in self.context['global_context'], self.context
except Exception,err: except Exception as err:
print "oops in customresponse (code) error %s" % err print "oops in customresponse (code) error %s" % err
print "context = ",self.context print "context = ",self.context
print traceback.format_exc() print traceback.format_exc()
...@@ -619,7 +619,7 @@ def sympy_check2(): ...@@ -619,7 +619,7 @@ def sympy_check2():
log.debug('nargs=%d, args=%s, kwargs=%s' % (nargs,args,kwargs)) log.debug('nargs=%d, args=%s, kwargs=%s' % (nargs,args,kwargs))
ret = fn(*args[:nargs],**kwargs) ret = fn(*args[:nargs],**kwargs)
except Exception,err: except Exception as err:
log.error("oops in customresponse (cfn) error %s" % err) log.error("oops in customresponse (cfn) error %s" % err)
# print "context = ",self.context # print "context = ",self.context
log.error(traceback.format_exc()) log.error(traceback.format_exc())
...@@ -746,12 +746,20 @@ main() ...@@ -746,12 +746,20 @@ main()
xml = self.xml xml = self.xml
self.url = xml.get('url') or "http://eecs1.mit.edu:8889/pyloncapa" # FIXME - hardcoded URL self.url = xml.get('url') or "http://eecs1.mit.edu:8889/pyloncapa" # FIXME - hardcoded URL
answer = xml.xpath('//*[@id=$id]//answer',id=xml.get('id'))[0] # FIXME - catch errors # answer = xml.xpath('//*[@id=$id]//answer',id=xml.get('id'))[0] # FIXME - catch errors
answer_src = answer.get('src') answer = xml.find('answer')
if answer_src is not None: if answer is not None:
self.code = self.system.filesystem.open('src/'+answer_src).read() answer_src = answer.get('src')
else: if answer_src is not None:
self.code = answer.text self.code = self.system.filesystem.open('src/'+answer_src).read()
else:
self.code = answer.text
else: # no <answer> stanza; get code from <script>
self.code = self.context['script_code']
if not self.code:
msg = '%s: Missing answer script code for externalresponse' % unicode(self)
msg += "\nSee XML source line %s" % getattr(self.xml,'sourceline','<unavailable>')
raise LoncapaProblemError(msg)
self.tests = xml.get('tests') self.tests = xml.get('tests')
...@@ -774,7 +782,7 @@ main() ...@@ -774,7 +782,7 @@ main()
try: try:
r = requests.post(self.url,data=payload) # call external server r = requests.post(self.url,data=payload) # call external server
except Exception,err: except Exception as err:
msg = 'Error %s - cannot connect to external server url=%s' % (err,self.url) msg = 'Error %s - cannot connect to external server url=%s' % (err,self.url)
log.error(msg) log.error(msg)
raise Exception(msg) raise Exception(msg)
...@@ -786,7 +794,7 @@ main() ...@@ -786,7 +794,7 @@ main()
try: try:
rxml = etree.fromstring(r.text) # response is XML; prase it rxml = etree.fromstring(r.text) # response is XML; prase it
except Exception,err: except Exception as err:
msg = 'Error %s - cannot parse response from external server r.text=%s' % (err,r.text) msg = 'Error %s - cannot parse response from external server r.text=%s' % (err,r.text)
log.error(msg) log.error(msg)
raise Exception(msg) raise Exception(msg)
...@@ -798,7 +806,7 @@ main() ...@@ -798,7 +806,7 @@ main()
cmap = CorrectMap() cmap = CorrectMap()
try: try:
submission = [student_answers[k] for k in idset] submission = [student_answers[k] for k in idset]
except Exception,err: except Exception as err:
log.error('Error %s: cannot get student answer for %s; student_answers=%s' % (err,self.answer_ids,student_answers)) log.error('Error %s: cannot get student answer for %s; student_answers=%s' % (err,self.answer_ids,student_answers))
raise Exception(err) raise Exception(err)
...@@ -808,7 +816,7 @@ main() ...@@ -808,7 +816,7 @@ main()
try: try:
rxml = self.do_external_request('get_score',extra_payload) rxml = self.do_external_request('get_score',extra_payload)
except Exception, err: except Exception as err:
log.error('Error %s' % err) log.error('Error %s' % err)
if self.system.DEBUG: if self.system.DEBUG:
cmap.set_dict(dict(zip(sorted(self.answer_ids), ['incorrect'] * len(idset) ))) cmap.set_dict(dict(zip(sorted(self.answer_ids), ['incorrect'] * len(idset) )))
...@@ -838,7 +846,7 @@ main() ...@@ -838,7 +846,7 @@ main()
try: try:
rxml = self.do_external_request('get_answers',{}) rxml = self.do_external_request('get_answers',{})
exans = json.loads(rxml.find('expected').text) exans = json.loads(rxml.find('expected').text)
except Exception,err: except Exception as err:
log.error('Error %s' % err) log.error('Error %s' % err)
if self.system.DEBUG: if self.system.DEBUG:
msg = '<font color=red size=+2>%s</font>' % str(err).replace('<','&lt;') msg = '<font color=red size=+2>%s</font>' % str(err).replace('<','&lt;')
...@@ -935,7 +943,7 @@ class FormulaResponse(LoncapaResponse): ...@@ -935,7 +943,7 @@ class FormulaResponse(LoncapaResponse):
except UndefinedVariable as uv: except UndefinedVariable as uv:
log.debug('formularesponse: undefined variable in given=%s' % given) log.debug('formularesponse: undefined variable in given=%s' % given)
raise StudentInputError(uv.message+" not permitted in answer") raise StudentInputError(uv.message+" not permitted in answer")
except Exception, err: except Exception as err:
#traceback.print_exc() #traceback.print_exc()
log.debug('formularesponse: error %s in formula' % err) log.debug('formularesponse: error %s in formula' % err)
raise StudentInputError("Error in formula") raise StudentInputError("Error in formula")
......
<section id="textbox_${id}" class="textbox"> <section id="textbox_${id}" class="textbox">
<textarea rows="${rows}" cols="${cols}" name="input_${id}" id="input_${id}">${value|h}</textarea> <textarea rows="${rows}" cols="${cols}" name="input_${id}" id="input_${id}"
% if hidden:
style="display:none;"
% endif
>${value|h}</textarea>
<span id="answer_${id}"></span> <span id="answer_${id}"></span>
...@@ -12,6 +16,9 @@ ...@@ -12,6 +16,9 @@
% elif state == 'incomplete': % elif state == 'incomplete':
<span class="incorrect" id="status_${id}"></span> <span class="incorrect" id="status_${id}"></span>
% endif % endif
% if hidden:
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
<br/> <br/>
<span class="debug">(${state})</span> <span class="debug">(${state})</span>
<br/> <br/>
......
...@@ -8,11 +8,17 @@ ...@@ -8,11 +8,17 @@
% elif state == 'incomplete': % elif state == 'incomplete':
<div class="incorrect" id="status_${id}"> <div class="incorrect" id="status_${id}">
% endif % endif
% if hidden:
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
<input type="text" name="input_${id}" id="input_${id}" value="${value}" <input type="text" name="input_${id}" id="input_${id}" value="${value}"
% if size: % if size:
size="${size}" size="${size}"
% endif % endif
% if hidden:
style="display:none;"
% endif
/> />
<p class="status"> <p class="status">
......
...@@ -11,8 +11,15 @@ ...@@ -11,8 +11,15 @@
% elif state == 'incomplete': % elif state == 'incomplete':
<div class="incorrect" id="status_${id}"> <div class="incorrect" id="status_${id}">
% endif % endif
% if hidden:
<div style="display:none;" name="${hidden}" inputid="input_${id}" />
% endif
<input type="text" name="input_${id}" id="input_${id}" value="${value}" class="math" size="${size if size else ''}" /> <input type="text" name="input_${id}" id="input_${id}" value="${value}" class="math" size="${size if size else ''}"
% if hidden:
style="display:none;"
% endif
/>
<p class="status"> <p class="status">
% if state == 'unsubmitted': % if state == 'unsubmitted':
......
...@@ -179,7 +179,12 @@ class CapaModule(XModule): ...@@ -179,7 +179,12 @@ class CapaModule(XModule):
score = d['score'] score = d['score']
total = d['total'] total = d['total']
if total > 0: if total > 0:
return Progress(score, total) try:
return Progress(score, total)
except Exception as err:
if self.DEBUG:
return None
raise
return None return None
def get_html(self): def get_html(self):
...@@ -193,7 +198,18 @@ class CapaModule(XModule): ...@@ -193,7 +198,18 @@ class CapaModule(XModule):
'''Return html for the problem. Adds check, reset, save buttons '''Return html for the problem. Adds check, reset, save buttons
as necessary based on the problem config and state.''' as necessary based on the problem config and state.'''
html = self.lcp.get_html() try:
html = self.lcp.get_html()
except Exception, err:
if self.DEBUG:
log.exception(err)
msg = '[courseware.capa.capa_module] <font size="+1" color="red">Failed to generate HTML for problem %s</font>' % (self.filename)
msg += '<p>Error:</p><p><pre>%s</pre></p>' % str(err).replace('<','&lt;')
msg += '<p><pre>%s</pre></p>' % traceback.format_exc().replace('<','&lt;')
html = msg
else:
raise
content = {'name': self.metadata['display_name'], content = {'name': self.metadata['display_name'],
'html': html, 'html': html,
'weight': self.weight, 'weight': self.weight,
...@@ -394,14 +410,18 @@ class CapaModule(XModule): ...@@ -394,14 +410,18 @@ class CapaModule(XModule):
correct_map = self.lcp.grade_answers(answers) correct_map = self.lcp.grade_answers(answers)
except StudentInputError as inst: except StudentInputError as inst:
# TODO (vshnayder): why is this line here? # TODO (vshnayder): why is this line here?
self.lcp = LoncapaProblem(self.definition['data'], #self.lcp = LoncapaProblem(self.definition['data'],
id=lcp_id, state=old_state, system=self.system) # id=lcp_id, state=old_state, system=self.system)
traceback.print_exc() traceback.print_exc()
return {'success': inst.message} return {'success': inst.message}
except: except Exception, err:
# TODO: why is this line here? # TODO: why is this line here?
self.lcp = LoncapaProblem(self.definition['data'], #self.lcp = LoncapaProblem(self.definition['data'],
id=lcp_id, state=old_state, system=self.system) # id=lcp_id, state=old_state, system=self.system)
if self.DEBUG:
msg = "Error checking problem: " + str(err)
msg += '\nTraceback:\n' + traceback.format_exc()
return {'success':msg}
traceback.print_exc() traceback.print_exc()
raise Exception("error in capa_module") raise Exception("error in capa_module")
......
...@@ -71,6 +71,7 @@ class Settings(object): ...@@ -71,6 +71,7 @@ class Settings(object):
# Load the course settings as a dictionary # Load the course settings as a dictionary
course_settings = {} course_settings = {}
try: try:
# TODO: this doesn't work with multicourse
with open( settings.DATA_DIR + "/course_settings.json") as course_settings_file: with open( settings.DATA_DIR + "/course_settings.json") as course_settings_file:
course_settings_string = course_settings_file.read() course_settings_string = course_settings_file.read()
course_settings = json.loads(course_settings_string) course_settings = json.loads(course_settings_string)
......
...@@ -274,11 +274,24 @@ def add_histogram(module): ...@@ -274,11 +274,24 @@ def add_histogram(module):
histogram = grade_histogram(module_id) histogram = grade_histogram(module_id)
render_histogram = len(histogram) > 0 render_histogram = len(histogram) > 0
# TODO: fixme - no filename in module.xml in general (this code block for edx4edx)
# the following if block is for summer 2012 edX course development; it will change when the CMS comes online
if settings.MITX_FEATURES.get('DISPLAY_EDIT_LINK') and settings.DEBUG and module_xml.get('filename') is not None:
coursename = multicourse_settings.get_coursename_from_request(request)
github_url = multicourse_settings.get_course_github_url(coursename)
fn = module_xml.get('filename')
if module_xml.tag=='problem': fn = 'problems/' + fn # grrr
edit_link = (github_url + '/tree/master/' + fn) if github_url is not None else None
if module_xml.tag=='problem': edit_link += '.xml' # grrr
else:
edit_link = False
# Cast module.definition and module.metadata to dicts so that json can dump them # Cast module.definition and module.metadata to dicts so that json can dump them
# even though they are lazily loaded # even though they are lazily loaded
staff_context = {'definition': json.dumps(dict(module.definition), indent=4), staff_context = {'definition': json.dumps(dict(module.definition), indent=4),
'metadata': json.dumps(dict(module.metadata), indent=4), 'metadata': json.dumps(dict(module.metadata), indent=4),
'element_id': module.location.html_id(), 'element_id': module.location.html_id(),
'edit_link': edit_link,
'histogram': json.dumps(histogram), 'histogram': json.dumps(histogram),
'render_histogram': render_histogram, 'render_histogram': render_histogram,
'module_content': original_get_html()} 'module_content': original_get_html()}
...@@ -287,7 +300,6 @@ def add_histogram(module): ...@@ -287,7 +300,6 @@ def add_histogram(module):
module.get_html = get_html module.get_html = get_html
return module return module
def modx_dispatch(request, dispatch=None, id=None): def modx_dispatch(request, dispatch=None, id=None):
''' Generic view for extensions. This is where AJAX calls go. ''' Generic view for extensions. This is where AJAX calls go.
......
...@@ -117,6 +117,9 @@ def render_accordion(request, course, chapter, section): ...@@ -117,6 +117,9 @@ def render_accordion(request, course, chapter, section):
Returns (initialization_javascript, content)''' Returns (initialization_javascript, content)'''
if not course:
course = settings.COURSE_DEFAULT.replace('_',' ')
course_location = multicourse_settings.get_course_location(course) course_location = multicourse_settings.get_course_location(course)
toc = toc_for_course(request.user, request, course_location, chapter, section) toc = toc_for_course(request.user, request, course_location, chapter, section)
...@@ -142,9 +145,10 @@ def get_course(request, course): ...@@ -142,9 +145,10 @@ def get_course(request, course):
if course == None: if course == None:
if not settings.ENABLE_MULTICOURSE: if not settings.ENABLE_MULTICOURSE:
course = "6.002 Spring 2012" course = "edx4edx"
elif 'coursename' in request.session: elif 'coursename' in request.session:
course = request.session['coursename'] # use multicourse_settings, so that settings.COURSE_TITLE is set properly
course = multicourse_settings.get_coursename_from_request(request)
else: else:
course = settings.COURSE_DEFAULT course = settings.COURSE_DEFAULT
return course return course
...@@ -188,6 +192,19 @@ def index(request, course=None, chapter=None, section=None, ...@@ -188,6 +192,19 @@ def index(request, course=None, chapter=None, section=None,
# keep track of current course being viewed in django's request.session # keep track of current course being viewed in django's request.session
request.session['coursename'] = course request.session['coursename'] = course
# get default chapter & section from multicourse settings, if not provided
if chapter is None:
defchapter = multicourse_settings.get_course_default_chapter(course)
defsection = multicourse_settings.get_course_default_section(course)
if defchapter and defsection:
# jump there using redirect, so the user gets the right URL in their browser
newurl = '%s/courseware/%s/%s/%s/' % (settings.MITX_ROOT_URL,
get_course(request, course),
defchapter,
defsection)
log.debug('redirecting to %s' % newurl)
return redirect(newurl)
chapter = clean(chapter) chapter = clean(chapter)
section = clean(section) section = clean(section)
......
...@@ -94,6 +94,14 @@ def get_course_title(coursename): ...@@ -94,6 +94,14 @@ def get_course_title(coursename):
def get_course_number(coursename): def get_course_number(coursename):
return get_course_property(coursename, 'number') return get_course_property(coursename, 'number')
def get_course_github_url(coursename):
return get_course_property(coursename,'github_url')
def get_course_default_chapter(coursename):
return get_course_property(coursename,'default_chapter')
def get_course_default_section(coursename):
return get_course_property(coursename,'default_section')
def get_course_location(coursename): def get_course_location(coursename):
return get_course_property(coursename, 'location') return get_course_property(coursename, 'location')
'''
django admin pages for courseware model
'''
from student.models import *
from django.contrib import admin
from django.contrib.auth.models import User
admin.site.register(UserProfile)
admin.site.register(Registration)
admin.site.register(PendingNameChange)
...@@ -191,7 +191,9 @@ def create_account(request, post_override=None): ...@@ -191,7 +191,9 @@ def create_account(request, post_override=None):
up.save() up.save()
d={'name':post_vars['name'], d={'name':post_vars['name'],
'key':r.activation_key} 'key':r.activation_key,
'course_title' : settings.COURSE_TITLE,
}
subject = render_to_string('emails/activation_email_subject.txt',d) subject = render_to_string('emails/activation_email_subject.txt',d)
# Email subject *must not* contain newlines # Email subject *must not* contain newlines
...@@ -199,7 +201,11 @@ def create_account(request, post_override=None): ...@@ -199,7 +201,11 @@ def create_account(request, post_override=None):
message = render_to_string('emails/activation_email.txt',d) message = render_to_string('emails/activation_email.txt',d)
try: try:
if not settings.GENERATE_RANDOM_USER_CREDENTIALS: if settings.MITX_FEATURES.get('REROUTE_ACTIVATION_EMAIL'):
dest_addr = settings.MITX_FEATURES['REROUTE_ACTIVATION_EMAIL']
message = "Activation for %s (%s): %s\n" % (u,u.email,up.name) + '-'*80 + '\n\n' + message
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False)
elif not settings.GENERATE_RANDOM_USER_CREDENTIALS:
res=u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) res=u.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
except: except:
log.exception(sys.exc_info()) log.exception(sys.exc_info())
......
...@@ -38,6 +38,7 @@ MITX_FEATURES = { ...@@ -38,6 +38,7 @@ MITX_FEATURES = {
'SAMPLE' : False, 'SAMPLE' : False,
'USE_DJANGO_PIPELINE' : True, 'USE_DJANGO_PIPELINE' : True,
'DISPLAY_HISTOGRAMS_TO_STAFF' : True, 'DISPLAY_HISTOGRAMS_TO_STAFF' : True,
'REROUTE_ACTIVATION_EMAIL' : False, # nonempty string = address for all activation emails
} }
# Used for A/B testing # Used for A/B testing
......
...@@ -52,8 +52,8 @@ CACHES = { ...@@ -52,8 +52,8 @@ CACHES = {
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
################################ DEBUG TOOLBAR ################################# ################################ DEBUG TOOLBAR #################################
INSTALLED_APPS += ('debug_toolbar',) #INSTALLED_APPS += ('debug_toolbar',)
MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',) #MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
INTERNAL_IPS = ('127.0.0.1',) INTERNAL_IPS = ('127.0.0.1',)
DEBUG_TOOLBAR_PANELS = ( DEBUG_TOOLBAR_PANELS = (
......
"""
This config file runs the simplest dev environment using sqlite, and db-based
sessions. Assumes structure:
/envroot/
/db # This is where it'll write the database file
/mitx # The location of this repo
/log # Where we're going to write log files
"""
import socket
if 'eecs1' in socket.gethostname():
MITX_ROOT_URL = '/mitx2'
from .common import *
from .logsettings import get_logger_config
from .dev import *
if 'eecs1' in socket.gethostname():
MITX_ROOT_URL = '/mitx2'
#-----------------------------------------------------------------------------
# edx4edx content server
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
MITX_FEATURES['REROUTE_ACTIVATION_EMAIL'] = 'ichuang@mitx.mit.edu'
EDX4EDX_ROOT = ENV_ROOT / "data/edx4edx"
#EMAIL_BACKEND = 'django_ses.SESBackend'
#-----------------------------------------------------------------------------
# ichuang
DEBUG = True
ENABLE_MULTICOURSE = True # set to False to disable multicourse display (see lib.util.views.mitxhome)
QUICKEDIT = True
MAKO_TEMPLATES['course'] = [DATA_DIR, EDX4EDX_ROOT ]
#MITX_FEATURES['USE_DJANGO_PIPELINE'] = False
MITX_FEATURES['DISPLAY_HISTOGRAMS_TO_STAFF'] = False
MITX_FEATURES['DISPLAY_EDIT_LINK'] = True
COURSE_DEFAULT = "edx4edx"
COURSE_NAME = "edx4edx"
COURSE_NUMBER = "edX.01"
COURSE_TITLE = "edx4edx: edX Author Course"
SITE_NAME = "ichuang.mitx.mit.edu"
COURSE_SETTINGS = {'edx4edx': {'number' : 'edX.01',
'title' : 'edx4edx: edX Author Course',
'xmlpath': '/edx4edx/',
'github_url': 'https://github.com/MITx/edx4edx',
'active' : True,
'default_chapter' : 'Introduction',
'default_section' : 'edx4edx_Course',
},
}
#-----------------------------------------------------------------------------
MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + (
'ssl_auth.ssl_auth.NginxProxyHeaderMiddleware', # ssl authentication behind nginx proxy
)
AUTHENTICATION_BACKENDS = (
'ssl_auth.ssl_auth.SSLLoginBackend',
'django.contrib.auth.backends.ModelBackend',
)
INSTALLED_APPS = INSTALLED_APPS + (
'ssl_auth',
)
LOGIN_REDIRECT_URL = MITX_ROOT_URL + '/'
LOGIN_URL = MITX_ROOT_URL + '/'
...@@ -18,7 +18,17 @@ from .logsettings import get_logger_config ...@@ -18,7 +18,17 @@ from .logsettings import get_logger_config
from .dev import * from .dev import *
if 'eecs1' in socket.gethostname(): if 'eecs1' in socket.gethostname():
MITX_ROOT_URL = '/mitx2' # MITX_ROOT_URL = '/mitx2'
MITX_ROOT_URL = 'https://eecs1.mit.edu/mitx2'
#-----------------------------------------------------------------------------
# edx4edx content server
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
MITX_FEATURES['REROUTE_ACTIVATION_EMAIL'] = 'ichuang@mit.edu'
EDX4EDX_ROOT = ENV_ROOT / "data/edx4edx"
#EMAIL_BACKEND = 'django_ses.SESBackend'
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# ichuang # ichuang
...@@ -27,38 +37,90 @@ DEBUG = True ...@@ -27,38 +37,90 @@ DEBUG = True
ENABLE_MULTICOURSE = True # set to False to disable multicourse display (see lib.util.views.mitxhome) ENABLE_MULTICOURSE = True # set to False to disable multicourse display (see lib.util.views.mitxhome)
QUICKEDIT = True QUICKEDIT = True
# MITX_FEATURES['USE_DJANGO_PIPELINE'] = False MAKO_TEMPLATES['course'] = [DATA_DIR, EDX4EDX_ROOT ]
#MITX_FEATURES['USE_DJANGO_PIPELINE'] = False
MITX_FEATURES['DISPLAY_HISTOGRAMS_TO_STAFF'] = False MITX_FEATURES['DISPLAY_HISTOGRAMS_TO_STAFF'] = False
MITX_FEATURES['DISPLAY_EDIT_LINK'] = True
COURSE_SETTINGS = {'6.002_Spring_2012': {'number' : '6.002x', COURSE_SETTINGS = {'6.002x_Fall_2012': {'number' : '6.002x',
'title' : 'Circuits and Electronics', 'title' : 'Circuits and Electronics',
'xmlpath': '/6002x/', 'xmlpath': '/6002x-fall-2012/',
'active' : True, 'active' : True,
'default_chapter' : 'Week_1',
'default_section' : 'Administrivia_and_Circuit_Elements',
}, },
'8.02_Spring_2013': {'number' : '8.02x', '8.02_Spring_2013': {'number' : '8.02x',
'title' : 'Electricity &amp; Magnetism', 'title' : 'Electricity &amp; Magnetism',
'xmlpath': '/802x/', 'xmlpath': '/802x/',
'active' : True, 'github_url': 'https://github.com/MITx/8.02x',
}, 'active' : True,
'8.01_Spring_2013': {'number' : '8.01x', 'default_chapter' : 'Introduction',
'title' : 'Mechanics', 'default_section' : 'Introduction_%28Lewin_2002%29',
'xmlpath': '/801x/',
'active' : False,
}, },
'6.189_Spring_2013': {'number' : '6.189x', '6.189_Spring_2013': {'number' : '6.189x',
'title' : 'IAP Python Programming', 'title' : 'IAP Python Programming',
'xmlpath': '/6189-pytutor/', 'xmlpath': '/6.189x/',
'active' : True, 'github_url': 'https://github.com/MITx/6.189x',
'active' : True,
'default_chapter' : 'Week_1',
'default_section' : 'Variables_and_Binding',
}, },
'8.01_Summer_2012': {'number' : '8.01x', '8.01_Fall_2012': {'number' : '8.01x',
'title' : 'Mechanics', 'title' : 'Mechanics',
'xmlpath': '/801x-summer/', 'xmlpath': '/8.01x/',
'github_url': 'https://github.com/MITx/8.01x',
'active': True, 'active': True,
'default_chapter' : 'Mechanics_Online_Spring_2012',
'default_section' : 'Introduction_to_the_course',
}, },
'edx4edx': {'number' : 'edX.01', 'edx4edx': {'number' : 'edX.01',
'title' : 'edx4edx: edX Author Course', 'title' : 'edx4edx: edX Author Course',
'xmlpath': '/edx4edx/', 'xmlpath': '/edx4edx/',
'github_url': 'https://github.com/MITx/edx4edx',
'active' : True,
'default_chapter' : 'Introduction',
'default_section' : 'edx4edx_Course',
},
'7.03x_Fall_2012': {'number' : '7.03x',
'title' : 'Genetics',
'xmlpath': '/7.03x/',
'github_url': 'https://github.com/MITx/7.03x',
'active' : True,
'default_chapter' : 'Week_2',
'default_section' : 'ps1_question_1',
},
'3.091x_Fall_2012': {'number' : '3.091x',
'title' : 'Introduction to Solid State Chemistry',
'xmlpath': '/3.091x/',
'github_url': 'https://github.com/MITx/3.091x',
'active' : True,
'default_chapter' : 'Week_1',
'default_section' : 'Problem_Set_1',
},
'18.06x_Linear_Algebra': {'number' : '18.06x',
'title' : 'Linear Algebra',
'xmlpath': '/18.06x/',
'github_url': 'https://github.com/MITx/18.06x',
'default_chapter' : 'Unit_1',
'default_section' : 'Midterm_1',
'active' : True,
},
'6.00x_Fall_2012': {'number' : '6.00x',
'title' : 'Introduction to Computer Science and Programming',
'xmlpath': '/6.00x/',
'github_url': 'https://github.com/MITx/6.00x',
'active' : True,
'default_chapter' : 'Week_0',
'default_section' : 'Problem_Set_0',
},
'7.00x_Fall_2012': {'number' : '7.00x',
'title' : 'Introduction to Biology',
'xmlpath': '/7.00x/',
'github_url': 'https://github.com/MITx/7.00x',
'active' : True, 'active' : True,
'default_chapter' : 'Unit 1',
'default_section' : 'Introduction',
}, },
} }
......
# Settings for edx4edx production instance
from .aws import *
COURSE_NAME = "edx4edx"
COURSE_NUMBER = "edX.01"
COURSE_TITLE = "edx4edx: edX Author Course"
EDX4EDX_ROOT = ENV_ROOT / "data/edx4edx"
### Dark code. Should be enabled in local settings for devel.
QUICKEDIT = True
ENABLE_MULTICOURSE = True # set to False to disable multicourse display (see lib.util.views.mitxhome)
###
PIPELINE_CSS_COMPRESSOR = None
PIPELINE_JS_COMPRESSOR = None
COURSE_DEFAULT = 'edx4edx'
COURSE_SETTINGS = {'edx4edx': {'number' : 'edX.01',
'title' : 'edx4edx: edX Author Course',
'xmlpath': '/edx4edx/',
'github_url': 'https://github.com/MITx/edx4edx',
'active' : True,
'default_chapter' : 'Introduction',
'default_section' : 'edx4edx_Course',
},
}
STATICFILES_DIRS = [
PROJECT_ROOT / "static",
ASKBOT_ROOT / "askbot" / "skins",
("edx4edx", EDX4EDX_ROOT / "html"),
("circuits", DATA_DIR / "images"),
("handouts", DATA_DIR / "handouts"),
("subs", DATA_DIR / "subs"),
# This is how you would use the textbook images locally
# ("book", ENV_ROOT / "book_images")
]
MAKO_TEMPLATES['course'] = [DATA_DIR, EDX4EDX_ROOT ]
...@@ -24,7 +24,7 @@ def check_problem_code(ans,the_lcp,correct_answers,false_answers): ...@@ -24,7 +24,7 @@ def check_problem_code(ans,the_lcp,correct_answers,false_answers):
pfn += the_lcp.problem_id.replace('filename','') # add problem ID to dogfood problem name pfn += the_lcp.problem_id.replace('filename','') # add problem ID to dogfood problem name
update_problem(pfn,ans,filestore=the_lcp.system.filestore) update_problem(pfn,ans,filestore=the_lcp.system.filestore)
msg = '<hr width="100%"/>' msg = '<hr width="100%"/>'
msg += '<iframe src="%s/dogfood/filename%s" width="95%%" frameborder="1">No iframe support!</iframe>' % (settings.MITX_ROOT_URL,pfn) msg += '<iframe src="%s/dogfood/filename%s" width="95%%" height="400" frameborder="1">No iframe support!</iframe>' % (settings.MITX_ROOT_URL,pfn)
msg += '<hr width="100%"/>' msg += '<hr width="100%"/>'
endmsg = """<p><font size="-1" color="purple">Note: if the code text box disappears after clicking on "Check", endmsg = """<p><font size="-1" color="purple">Note: if the code text box disappears after clicking on "Check",
......
...@@ -25,7 +25,7 @@ import track.views ...@@ -25,7 +25,7 @@ import track.views
from lxml import etree from lxml import etree
from courseware.module_render import make_track_function, I4xSystem from courseware.module_render import make_track_function, I4xSystem, get_module
from courseware.models import StudentModule from courseware.models import StudentModule
from multicourse import multicourse_settings from multicourse import multicourse_settings
from student.models import UserProfile from student.models import UserProfile
...@@ -55,6 +55,7 @@ def update_problem(pfn,pxml,coursename=None,overwrite=True,filestore=None): ...@@ -55,6 +55,7 @@ def update_problem(pfn,pxml,coursename=None,overwrite=True,filestore=None):
else: else:
pfn2 = 'problems/%s.xml' % pfn pfn2 = 'problems/%s.xml' % pfn
fp = filestore.open(pfn2,'w') fp = filestore.open(pfn2,'w')
log.debug('[dogfood.update_problem] pfn2=%s' % pfn2)
if os.path.exists(pfn2) and not overwrite: return # don't overwrite if already exists and overwrite=False if os.path.exists(pfn2) and not overwrite: return # don't overwrite if already exists and overwrite=False
pxmls = pxml if type(pxml) in [str,unicode] else etree.tostring(pxml,pretty_print=True) pxmls = pxml if type(pxml) in [str,unicode] else etree.tostring(pxml,pretty_print=True)
...@@ -71,7 +72,7 @@ def df_capa_problem(request, id=None): ...@@ -71,7 +72,7 @@ def df_capa_problem(request, id=None):
# "WARNING: UNDEPLOYABLE CODE. FOR DEV USE ONLY." # "WARNING: UNDEPLOYABLE CODE. FOR DEV USE ONLY."
if settings.DEBUG: if settings.DEBUG:
print '[lib.dogfood.df_capa_problem] id=%s' % id log.debug('[lib.dogfood.df_capa_problem] id=%s' % id)
if not 'coursename' in request.session: if not 'coursename' in request.session:
coursename = DOGFOOD_COURSENAME coursename = DOGFOOD_COURSENAME
...@@ -86,7 +87,7 @@ def df_capa_problem(request, id=None): ...@@ -86,7 +87,7 @@ def df_capa_problem(request, id=None):
try: try:
xml = content_parser.module_xml(request.user, module, 'id', id, coursename) xml = content_parser.module_xml(request.user, module, 'id', id, coursename)
except Exception,err: except Exception,err:
print "[lib.dogfood.df_capa_problem] error in calling content_parser: %s" % err log.error("[lib.dogfood.df_capa_problem] error in calling content_parser: %s" % err)
xml = None xml = None
# if problem of given ID does not exist, then create it # if problem of given ID does not exist, then create it
...@@ -96,7 +97,7 @@ def df_capa_problem(request, id=None): ...@@ -96,7 +97,7 @@ def df_capa_problem(request, id=None):
if not m: if not m:
raise Exception,'[lib.dogfood.df_capa_problem] Illegal problem id %s' % id raise Exception,'[lib.dogfood.df_capa_problem] Illegal problem id %s' % id
pfn = m.group(1) pfn = m.group(1)
print '[lib.dogfood.df_capa_problem] creating new problem pfn=%s' % pfn log.debug('[lib.dogfood.df_capa_problem] creating new problem pfn=%s' % pfn)
# add problem to course.xml # add problem to course.xml
fn = settings.DATA_DIR + xp + 'course.xml' fn = settings.DATA_DIR + xp + 'course.xml'
...@@ -126,7 +127,7 @@ def df_capa_problem(request, id=None): ...@@ -126,7 +127,7 @@ def df_capa_problem(request, id=None):
'groups' : groups} 'groups' : groups}
filename = xp + 'course.xml' filename = xp + 'course.xml'
cache_key = filename + "_processed?dev_content:" + str(options['dev_content']) + "&groups:" + str(sorted(groups)) cache_key = filename + "_processed?dev_content:" + str(options['dev_content']) + "&groups:" + str(sorted(groups))
print '[lib.dogfood.df_capa_problem] cache_key = %s' % cache_key log.debug('[lib.dogfood.df_capa_problem] cache_key = %s' % cache_key)
#cache.delete(cache_key) #cache.delete(cache_key)
tree = content_parser.course_xml_process(xml) # add ID tags tree = content_parser.course_xml_process(xml) # add ID tags
cache.set(cache_key,etree.tostring(tree),60) cache.set(cache_key,etree.tostring(tree),60)
...@@ -134,7 +135,7 @@ def df_capa_problem(request, id=None): ...@@ -134,7 +135,7 @@ def df_capa_problem(request, id=None):
xml = content_parser.module_xml(request.user, module, 'id', id, coursename) xml = content_parser.module_xml(request.user, module, 'id', id, coursename)
if not xml: if not xml:
print "[lib.dogfood.df_capa_problem] problem xml not found!" log.debug("[lib.dogfood.df_capa_problem] problem xml not found!")
# add problem ID to list so that is_staff check can be bypassed # add problem ID to list so that is_staff check can be bypassed
request.session['dogfood_id'] = id request.session['dogfood_id'] = id
...@@ -171,6 +172,31 @@ def quickedit(request, id=None, qetemplate='quickedit.html',coursename=None): ...@@ -171,6 +172,31 @@ def quickedit(request, id=None, qetemplate='quickedit.html',coursename=None):
def get_lcp(coursename,id): def get_lcp(coursename,id):
# Grab the XML corresponding to the request from course.xml # Grab the XML corresponding to the request from course.xml
# create empty student state for this problem, if not previously existing
s = StudentModule.objects.filter(student=request.user,
module_id=id)
student_module_cache = list(s) if s is not None else []
#if len(s) == 0 or s is None:
# smod=StudentModule(student=request.user,
# module_type = 'problem',
# module_id=id,
# state=instance.get_state())
# smod.save()
# student_module_cache = [smod]
module = 'problem'
module_xml = etree.XML(content_parser.module_xml(request.user, module, 'id', id, coursename))
module_id = module_xml.get('id')
log.debug("module_id = %s" % module_id)
(instance,smod,module_type) = get_module(request.user, request, module_xml, student_module_cache, position=None)
log.debug('[dogfood.views] instance=%s' % instance)
lcp = instance.lcp
log.debug('[dogfood.views] lcp=%s' % lcp)
pxml = lcp.tree
pxmls = etree.tostring(pxml,pretty_print=True)
return instance, pxmls
def old_get_lcp(coursename,id):
# Grab the XML corresponding to the request from course.xml
module = 'problem' module = 'problem'
xml = content_parser.module_xml(request.user, module, 'id', id, coursename) xml = content_parser.module_xml(request.user, module, 'id', id, coursename)
...@@ -280,7 +306,8 @@ def quickedit_git_reload(request): ...@@ -280,7 +306,8 @@ def quickedit_git_reload(request):
if 'gitupdate' in request.POST: if 'gitupdate' in request.POST:
import os # FIXME - put at top? import os # FIXME - put at top?
cmd = "cd ../data%s; git reset --hard HEAD; git pull origin %s" % (xp,xp.replace('/','')) #cmd = "cd ../data%s; git reset --hard HEAD; git pull origin %s" % (xp,xp.replace('/',''))
cmd = "cd ../data%s; ./GITRELOAD '%s'" % (xp,xp.replace('/',''))
msg += '<p>cmd: %s</p>' % cmd msg += '<p>cmd: %s</p>' % cmd
ret = os.popen(cmd).read() ret = os.popen(cmd).read()
msg += '<p><pre>%s</pre></p>' % ret.replace('<','&lt;') msg += '<p><pre>%s</pre></p>' % ret.replace('<','&lt;')
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
# Python functions which duplicate the standard comparison functions available to LON-CAPA problems. # Python functions which duplicate the standard comparison functions available to LON-CAPA problems.
# Used in translating LON-CAPA problems to i4x problem specification language. # Used in translating LON-CAPA problems to i4x problem specification language.
from __future__ import division
import random import random
import math
def lc_random(lower,upper,stepsize): def lc_random(lower,upper,stepsize):
''' '''
...@@ -15,3 +17,20 @@ def lc_random(lower,upper,stepsize): ...@@ -15,3 +17,20 @@ def lc_random(lower,upper,stepsize):
choices = [lower+x*stepsize for x in range(nstep)] choices = [lower+x*stepsize for x in range(nstep)]
return random.choice(choices) return random.choice(choices)
def lc_choose(index,*args):
'''
return args[index]
'''
try:
return args[int(index)-1]
except Exception,err:
pass
if len(args):
return args[0]
raise Exception,"loncapa_check.lc_choose error, index=%s, args=%s" % (index,args)
deg2rad = math.pi/180.0
rad2deg = 180.0/math.pi
...@@ -231,6 +231,9 @@ def symmath_check(expect,ans,dynamath=None,options=None,debug=None): ...@@ -231,6 +231,9 @@ def symmath_check(expect,ans,dynamath=None,options=None,debug=None):
dm = my_evalf(sympy.Matrix(fexpect)-sympy.Matrix(xgiven),chop=True) dm = my_evalf(sympy.Matrix(fexpect)-sympy.Matrix(xgiven),chop=True)
if abs(dm.vec().norm().evalf())<threshold: if abs(dm.vec().norm().evalf())<threshold:
return {'ok': True,'msg': msg} return {'ok': True,'msg': msg}
except sympy.ShapeError:
msg += "<p>Error - your input vector or matrix has the wrong dimensions"
return {'ok':False,'msg':msg}
except Exception,err: except Exception,err:
msg += "<p>Error %s in comparing expected (a list) and your answer</p>" % str(err).replace('<','&lt;') msg += "<p>Error %s in comparing expected (a list) and your answer</p>" % str(err).replace('<','&lt;')
if DEBUG: msg += "<p/><pre>%s</pre>" % traceback.format_exc() if DEBUG: msg += "<p/><pre>%s</pre>" % traceback.format_exc()
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
% endfor % endfor
## add a link to allow course.xml to be reloaded from the git content repo ## add a link to allow course.xml to be reloaded from the git content repo
% if settings.QUICKEDIT: ##% if settings.QUICKEDIT:
<h3><a href="#">quickedit</a></h3> ## <h3><a href="#">quickedit</a></h3>
<ul><li><a href="${MITX_ROOT_URL}/quickedit/course.xml">gitreload</a></li></ul> ## <ul><li><a href="${MITX_ROOT_URL}/quickedit/course.xml">gitreload</a></li></ul>
% endif ##% endif
<%inherit file="main.html" /> <%inherit file="main.html" />
<%block name="bodyclass">courseware</%block> <%block name="bodyclass">courseware</%block>
<%block name="title"><title>Courseware – MITx 6.002x</title></%block> <%block name="title"><title>Courseware – edX</title></%block>
<%include file="navigation.html" args="active_page='courseware'" /> <%include file="navigation.html" args="active_page='courseware'" />
<section class="main-content"> <section class="main-content">
<section class="outside-app"> <section class="outside-app">
<h1>There has been an error on the <em>MITx</em> servers</h1> <h1>There has been an error on the <em>edX</em> servers</h1>
<p>We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p> <p>We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p>
</section> </section>
</section> </section>
<!-- TODO: Add pattern field to username. See HTML5 cookbook, page 84 for details--> <!-- TODO: Add pattern field to username. See HTML5 cookbook, page 84 for details-->
<div name="enroll_form" id="enroll_form"> <div name="enroll_form" id="enroll_form">
<h1>Enroll in 6.002x Circuits &amp; Electronics</h1> <h1>Enroll in edx4edx</h1>
<!--[if lte IE 8]> <!--[if lte IE 8]>
<p class="ie-warning"> Enrollment requires a modern web browser with JavaScript enabled. You don't have this. You can&rsquo;t enroll without upgrading, since you couldn&rsquo;t take the course without upgrading. Feel free to download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Mozilla Firefox</a> or <a href="http://support.google.com/chrome/bin/answer.py?hl=en&answer=95346">Google Chrome</a>, for free, to enroll and take this course.</p> <p class="ie-warning"> Enrollment requires a modern web browser with JavaScript enabled. You don't have this. You can&rsquo;t enroll without upgrading, since you couldn&rsquo;t take the course without upgrading. Feel free to download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Mozilla Firefox</a> or <a href="http://support.google.com/chrome/bin/answer.py?hl=en&answer=95346">Google Chrome</a>, for free, to enroll and take this course.</p>
<![endif]--> <![endif]-->
<p class="disclaimer"> <p class="disclaimer">
Please note that 6.002x has now passed its half-way point. The midterm exam and several assignment due dates for 6.002x have already passed. It is now impossible for newly enrolled students to earn a passing grade and a completion certificate for the course. However, new students have access to all of the course material that has been released for the course, so you are welcome to enroll and browse the course. </p> </p>
<form name="enroll" id="enroll_form" method="get"> <form name="enroll" id="enroll_form" method="get">
<fieldset><% if 'error' in locals(): e = error %> <fieldset><% if 'error' in locals(): e = error %>
...@@ -35,7 +35,7 @@ Please note that 6.002x has now passed its half-way point. The midterm exam and ...@@ -35,7 +35,7 @@ Please note that 6.002x has now passed its half-way point. The midterm exam and
<label>Full name*<span class="ui-icon ui-icon-help" id="spinner_name" style="display:inline-block;"></span></label> <label>Full name*<span class="ui-icon ui-icon-help" id="spinner_name" style="display:inline-block;"></span></label>
<input name="name" id="ca_name" type="text" /> <input name="name" id="ca_name" type="text" />
<div class="tip" id="sregion_name">If you successfully complete the course, you will receive an electronic certificate of accomplishment from <i>MITx</i> with this name on it.</div> <div class="tip" id="sregion_name">If you successfully complete the course, you will receive an electronic certificate of accomplishment from <i>edX</i> with this name on it.</div>
</li> </li>
<li class="location"> <li class="location">
......
Someone, hopefully you, signed up for an account for MITx's on-line Someone, hopefully you, signed up for an account for edX's on-line
offering of 6.002 using this email address. If it was you, and you'd offering of "${ course_title}" using this email address. If it was
like to activate and use your account, copy and paste this address you, and you'd like to activate and use your account, copy and paste
into your web browser's address bar: this address into your web browser's address bar:
% if is_secure: % if is_secure:
https://${ site }/activate/${ key } https://${ site }/activate/${ key }
% else: % else:
http://${ site }/activate/${ key } http://edx4edx.mitx.mit.edu/activate/${ key }
% endif % endif
If you didn't request this, you don't need to do anything; you won't If you didn't request this, you don't need to do anything; you won't
receive any more email from us. Please do not reply to this e-mail; if receive any more email from us. Please do not reply to this e-mail; if
you require assistance, check the help section of the MITx web site. you require assistance, check the help section of the edX web site.
Your account for MITx's on-line 6.002 Your account for edX's on-line ${course_title} course
...@@ -4,24 +4,24 @@ ...@@ -4,24 +4,24 @@
<div> <div>
<h1> Collaboration Policy </h1> <h1> Collaboration Policy </h1>
<p> By enrolling in a course on <i>MITx</i>, you are joining a <p> By enrolling in a course on <i>edX</i>, you are joining a
special worldwide community of learners. The aspiration special worldwide community of learners. The aspiration
of <i>MITx</i> is to provide anyone in the world who has the of <i>edX</i> is to provide anyone in the world who has the
motivation and ability to engage MIT coursework the opportunity motivation and ability to engage edX coursework the opportunity
to attain the best MIT-based educational experience that to attain the best edX-based educational experience that
Internet technology enables. You are part of the community who Internet technology enables. You are part of the community who
will help <i>MITx</i> achieve this goal. will help <i>edX</i> achieve this goal.
<p> <i>MITx</i> depends upon your motivation to learn the material <p> <i>edX</i> depends upon your motivation to learn the material
and to do so with honesty. In order to participate and to do so with honesty. In order to participate
in <i>MITx</i>, you must agree to the Honor Code below and any in <i>edX</i>, you must agree to the Honor Code below and any
additional terms specific to a class. This Honor Code, and any additional terms specific to a class. This Honor Code, and any
additional terms, will be posted on each class website. additional terms, will be posted on each class website.
<div style="color:darkred;"> <div style="color:darkred;">
<h2> <i>MITx</i> Honor Code Pledge</h2> <h2> <i>edX</i> Honor Code Pledge</h2>
<p> By enrolling in an <i>MITx</i> course, I agree that I will: <p> By enrolling in an <i>edX</i> course, I agree that I will:
<ul> <ul>
<li> Complete all mid-terms and final exams with my own work <li> Complete all mid-terms and final exams with my own work
...@@ -35,14 +35,14 @@ ...@@ -35,14 +35,14 @@
assess student performance. assess student performance.
</ul> </ul>
</div> </div>
<p> Unless otherwise indicated by the instructor of an <i>MITx</i> <p> Unless otherwise indicated by the instructor of an <i>edX</i>
course, learners on <i>MITx</i> are encouraged to: course, learners on <i>edX</i> are encouraged to:
<ul> <ul>
<li> Collaborate with others on the lecture videos, exercises, <li> Collaborate with others on the lecture videos, exercises,
homework and labs. homework and labs.
<li> Discuss with others general concepts and materials in <li> Discuss with others general concepts and materials in
each course. each course.
<li> Present ideas and written work to fellow <i>MITx</i> <li> Present ideas and written work to fellow <i>edX</i>
learners or others for comment or criticism. learners or others for comment or criticism.
</ul> </ul>
</div> </div>
......
<%inherit file="marketing.html" /> <%inherit file="marketing.html" />
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
<%block name="title">MITx 6.002x: Circuits & Electronics</%block> <%block name="title">edx4edx author course</%block>
<%block name="description">6.002x (Circuits and Electronics) is an experimental on-line adaptation of MIT's first undergraduate analog design course: 6.002.</%block> <%block name="description">edx4edx</%block>
<%block name="keywords">MITx, circuits, electronics, EECS, electrical engineering, analog circuits, digital circuits, online learning, MIT, online laboratory, education, learners, undergraduate, certificate</%block> <%block name="keywords">MITx, edx4edx</%block>
<%block name="header_text"> <%block name="header_text">
<section class="course"> <section class="course">
<section> <section>
<h1>Circuits &amp; Electronics</h1> <h1>edx4edx</h1>
<h2>6.002x</h2> <h2>edX Author Course</h2>
<a class="enroll" rel="leanModal" href="/info">View 6.002x Circuits <span>&amp;</span> Electronics as a guest</a> <a class="enroll" rel="leanModal" href="#enroll"><noscript>In
<a class="enroll" rel="leanModal" href="#enroll"><noscript>In order to</noscript> Enroll in 6.002x Circuits <span>&amp;</span> Electronics <noscript>you need to have javascript enabled</noscript></a> order to</noscript> Enroll in edx4edx <noscript>you need to have javascript enabled</noscript></a>
</section> </section>
<p>6.002x (Circuits and Electronics) is an experimental on-line adaptation of MIT&rsquo;s first undergraduate analog design course: 6.002. This course is running, free of charge, for students worldwide from March 5, 2012 through June 8, 2012.</p> <p>edx4edx is a course for prospective edX course authors</p>
</section> </section>
</%block> </%block>
<%block name="header_class">course</%block> <%block name="header_class">course</%block>
<section class="index-content"> <section class="index-content">
<section class="about-course">
<section class="about-info">
<h1>About 6.002x</h1>
<p>6.002x (Circuits and Electronics) is designed to serve as a first course in an undergraduate electrical engineering (EE), or electrical engineering and computer science (EECS) curriculum. At MIT, 6.002 is in the core of department subjects required for all undergraduates in EECS.</p>
<p>The course introduces engineering in the context of the lumped circuit abstraction. Topics covered include: resistive elements and networks; independent and dependent sources; switches and MOS transistors; digital abstraction; amplifiers; energy storage elements; dynamics of first- and second-order networks; design in the time and frequency domains; and analog and digital circuits and applications. Design and lab exercises are also significant components of the course. You should expect to spend approximately 10 hours per week on the course.</p>
</section>
<section class="on-mitx">
<h1>6.002x on <em>MITx</em></h1> <!-- Link doesn't need to be here, but there should be some way to get back to main MITx site -->
<p>If you successfully complete the course, you will receive an electronic certificate of accomplishment from <em>MITx</em>. This certificate will indicate that you earned it from <em>MITx&rsquo;s</em> pilot course. In this prototype version, <em>MITx</em> will not require that you be tested in a testing center or otherwise have your identity certified in order to receive this certificate.</p>
<p>The course uses the textbook Foundations of Analog and Digital Electronic Circuits, by Anant Agarwal and Jeffrey H. Lang. Morgan Kaufmann Publishers, Elsevier, July 2005. While recommended, the book is not required: relevant sections will be provided electronically as part of the online course for personal use in connection with this course only. The copyright for the book is owned by Elsevier. The book can be purchased on <a href="http://www.amazon.com/exec/obidos/ASIN/1558607358/ref=nosim/mitopencourse-20" target="_blank">Amazon</a>.</p>
</section>
<section class="requirements">
<h1> Requirements </h1>
<p>In order to succeed in this course, you must have taken an AP level physics course in electricity and magnetism. You must know basic calculus and linear algebra and have some background in differential equations. Since more advanced mathematics will not show up until the second half of the course, the first half of the course will include an optional remedial differential equations component for those who need it.</p>
<p>The course web site was developed and tested primarily with
Google Chrome. We support current versions of Mozilla Firefox as
well. The video player is designed to work with Flash. While we
provide a partial non-Flash fallback for the video, as well as
partial support for Internet Explorer, other browsers, and
tablets, portions of the functionality will be unavailable. </p>
</section>
<section class="cta">
<a class="enroll" rel="leanModal" href="/info">View 6.002x Circuits &amp; Electronics as a guest</a>
<a class="enroll" rel="leanModal" href="#enroll"><noscript>In order to</noscript> Enroll in 6.002x Circuits &amp; Electronics <noscript>you need to have javascript enabled</noscript></a>
</section>
</section>
<section class="staff">
<h1>About the course staff</h1>
<ul>
<li>
<img src="${static.url('staff/agarwal-mit-news-small.jpg')}" alt="Anant Agarwal">
<h2>Anant Agarwal</h2>
<p>Director of MIT&rsquo;s Computer Science and Artificial Intelligence Laboratory (CSAIL) and a professor of the Electrical Engineering and Computer Science department at MIT. His research focus is in parallel computer architectures and cloud software systems, and he is a founder of several successful startups, including Tilera, a company that produces scalable multicore processors. Prof. Agarwal won MIT&rsquo;s Smullin and Jamieson prizes for teaching and co-authored the course textbook &ldquo;Foundations of Analog and Digital Electronic Circuits.&rdquo;</p></li>
<li>
<img src="${static.url('staff/gjs-small.jpg')}" alt="Gerald Sussman">
<h2>Gerald Sussman</h2>
<p>Professor of Electrical Engineering at MIT. He is a well known educator in the computer science community, perhaps best known as the author of Structure and Interpretation of Computer Programs, which is universally acknowledged as one of the top ten textbooks in computer science, and as the creator of Scheme, a popular teaching language. His research spans a range of topics, from artificial intelligence, to physics and chaotic systems, to supercomputer design.</p></li>
<li>
<img src="${static.url('staff/pmitros-small.jpg')}" alt="Piotr Mitros">
<h2>Piotr Mitros</h2>
<p>Research Scientist at MIT. His research focus is in finding ways to apply techniques from control systems to optimizing the learning process. Dr. Mitros has worked as an analog designer at Texas Instruments, Talking Lights, and most recently, designed the analog front end for a novel medical imaging modality for Rhythmia Medical.</p></li>
</ul>
</section>
</section> </section>
<div id="enroll" class="leanModal_box" name="enroll"><%include file="create_account.html" /></div> <div id="enroll" class="leanModal_box" name="enroll"><%include file="create_account.html" /></div>
......
...@@ -17,7 +17,7 @@ $(document).ready(function(){ ...@@ -17,7 +17,7 @@ $(document).ready(function(){
</script> </script>
</%block> </%block>
<%block name="title"><title>Course Info - MITx 6.002x</title></%block> <%block name="title"><title>Course Info - edx4edx x</title></%block>
<%include file="navigation.html" args="active_page='info'" /> <%include file="navigation.html" args="active_page='info'" />
......
<!-- TODO: http://docs.jquery.com/Plugins/Validation --> <!-- TODO: http://docs.jquery.com/Plugins/Validation -->
<div id="login_div"> <div id="login_div">
<header> <header>
<h1>Log in to MITx</h1> <h1>Log in to edX</h1>
<p class="no-account">If you don&rsquo;t have an account yet, <a href="#enroll" rel="leanModal">please enroll here</a></p> <p class="no-account">If you don&rsquo;t have an account yet, <a href="#enroll" rel="leanModal">please enroll here</a></p>
</header> </header>
<!--[if lte IE 9]> <!--[if lte IE 9]>
<p class="ie-warning">You are using a browser that is not supported by <em>MITx</em>, and you might not be able to complete pieces of the course. Please download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Firefox</a> or <a href="https://www.google.com/chrome">Chrome</a> to get the full experience.</p> <p class="ie-warning">You are using a browser that is not supported by <em>edX</em>, and you might not be able to complete pieces of the course. Please download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Firefox</a> or <a href="https://www.google.com/chrome">Chrome</a> to get the full experience.</p>
<![endif]--> <![endif]-->
<form id="login_form" method="post"> <form id="login_form" method="post">
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<%block name="title"><title>MITx 6.002x</title></%block> <%block name="title"><title>edX</title></%block>
<link rel="stylesheet" href="${static.url('js/jquery.treeview.css')}" type="text/css" media="all" /> <link rel="stylesheet" href="${static.url('js/jquery.treeview.css')}" type="text/css" media="all" />
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
<body class="<%block name='bodyclass'/>"> <body class="<%block name='bodyclass'/>">
<!--[if lte IE 9]> <!--[if lte IE 9]>
<p class="ie-warning">You are using a browser that is not supported by <em>MITx</em>, and you might not be able to complete pieces of the course. Please download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Firefox</a> or <a href="https://www.google.com/chrome">Chrome</a> to get the full experience.</p> <p class="ie-warning">You are using a browser that is not supported by <em>edX</em>, and you might not be able to complete pieces of the course. Please download the latest version of <a href="http://www.mozilla.org/en-US/firefox/new/">Firefox</a> or <a href="https://www.google.com/chrome">Chrome</a> to get the full experience.</p>
<![endif]--> <![endif]-->
${self.body()} ${self.body()}
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
</footer> </footer>
<div id="feedback_div" class="leanModal_box"> <div id="feedback_div" class="leanModal_box">
<h1>Feedback for MITx</h1> <h1>Feedback for edX</h1>
<p>Found a bug? Got an idea for improving our system? Let us know.</p> <p>Found a bug? Got an idea for improving our system? Let us know.</p>
<form> <form>
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
<hgroup> <hgroup>
<h1><em> <h1><em>
% if settings.ENABLE_MULTICOURSE: % if settings.ENABLE_MULTICOURSE:
<a href="${ MITX_ROOT_URL }/mitxhome" style="color:black;">MITx</a> <a href="${ MITX_ROOT_URL }/mitxhome" style="color:black;">edX</a>
% else: % else:
MITx edX
% endif % endif
</em></h1> </em></h1>
<h2><a href="${ MITX_ROOT_URL }/courseware/">${ settings.COURSE_TITLE }</a></h2> <h2><a href="${ MITX_ROOT_URL }/courseware/">${ settings.COURSE_TITLE }</a></h2>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<%namespace name='static' file='static_content.html'/> <%namespace name='static' file='static_content.html'/>
<%namespace name="profile_graphs" file="profile_graphs.js"/> <%namespace name="profile_graphs" file="profile_graphs.js"/>
<%block name="title"><title>Profile - MITx 6.002x</title></%block> <%block name="title"><title>Profile - edX 6.002x</title></%block>
<%! <%!
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -234,10 +234,10 @@ $(function() { ...@@ -234,10 +234,10 @@ $(function() {
<form id="change_name_form"> <form id="change_name_form">
<div id="change_name_error"> </div> <div id="change_name_error"> </div>
<fieldset> <fieldset>
<p>To uphold the credibility of MITx certificates, name changes must go through an approval process. A member of the course staff will review your request, and if approved, update your information. Please allow up to a week for your request to be processed. Thank you.</p> <p>To uphold the credibility of edX certificates, name changes must go through an approval process. A member of the course staff will review your request, and if approved, update your information. Please allow up to a week for your request to be processed. Thank you.</p>
<ul> <ul>
<li> <li>
<label>Enter your desired full name, as it will appear on the MITx Certificate: </label> <label>Enter your desired full name, as it will appear on the edX Certificate: </label>
<input id="new_name_field" value="" type="text" /> <input id="new_name_field" value="" type="text" />
</li> </li>
<li> <li>
...@@ -278,7 +278,7 @@ $(function() { ...@@ -278,7 +278,7 @@ $(function() {
</div> </div>
<div id="deactivate-account" class="leanModal_box"> <div id="deactivate-account" class="leanModal_box">
<h1>Deactivate MITx Account</h1> <h1>Deactivate edX Account</h1>
<p>Once you deactivate you&rsquo;re MIT<em>x</em> account you will no longer recieve updates and new class announcements from MIT<em>x</em>.</p> <p>Once you deactivate you&rsquo;re MIT<em>x</em> account you will no longer recieve updates and new class announcements from MIT<em>x</em>.</p>
<p>If you&rsquo;d like to still get updates and new class announcements you can just <a href="#unenroll" rel="leanModal">unenroll</a> and keep your account active.</p> <p>If you&rsquo;d like to still get updates and new class announcements you can just <a href="#unenroll" rel="leanModal">unenroll</a> and keep your account active.</p>
...@@ -287,7 +287,7 @@ $(function() { ...@@ -287,7 +287,7 @@ $(function() {
<fieldset> <fieldset>
<ul> <ul>
<li> <li>
<input type="submit" id="" value="Yes, I don't want an MITx account or hear about any new classes or updates to MITx" /> <input type="submit" id="" value="Yes, I don't want an edX account or hear about any new classes or updates to edX" />
</li> </li>
</ul> </ul>
</fieldset> </fieldset>
...@@ -296,14 +296,14 @@ $(function() { ...@@ -296,14 +296,14 @@ $(function() {
<div id="unenroll" class="leanModal_box"> <div id="unenroll" class="leanModal_box">
<h1>Unenroll from 6.002x</h1> <h1>Unenroll from 6.002x</h1>
<p>Please note: you will still receive updates and new class announcements from MIT<em>x</em>. If you don&rsquo;t wish to receive any more updates or announcements <a href="#deactivate-account" rel="leanModal">deactivate your account</a>.</p> <p>Please note: you will still receive updates and new class announcements from ed<em>X</em>. If you don&rsquo;t wish to receive any more updates or announcements <a href="#deactivate-account" rel="leanModal">deactivate your account</a>.</p>
<form id="unenroll_form"> <form id="unenroll_form">
<div id="unenroll_error"> </div> <div id="unenroll_error"> </div>
<fieldset> <fieldset>
<ul> <ul>
<li> <li>
<input type="submit" id="" value="Yes, I want to unenroll from 6.002x but still hear about any new classes or updates to MITx" /> <input type="submit" id="" value="Yes, I want to unenroll from 6.002x but still hear about any new classes or updates to edX" />
</li> </li>
</ul> </ul>
</fieldset> </fieldset>
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
<%include file="mathjax_include.html" /> <%include file="mathjax_include.html" />
</head> </head>
<body class="courseware"> <body class="courseware" style="text-align:left;" >
<style type="text/css"> <style type="text/css">
......
<%inherit file="main.html" /> <%inherit file="main.html" />
<section class="outside-app"> <section class="outside-app">
<h1>Currently the <em>MITx</em> servers are down</h1> <h1>Currently the <em>edX</em> servers are down</h1>
<p>Our staff is currently working to get the site back up as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p> <p>Our staff is currently working to get the site back up as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p>
</section> </section>
<%inherit file="main.html" /> <%inherit file="main.html" />
<section class="outside-app"> <section class="outside-app">
<h1>There has been an error on the <em>MITx</em> servers</h1> <h1>There has been an error on the <em>edX</em> servers</h1>
<p>Our staff is currently working to get the site back up as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p> <p>Our staff is currently working to get the site back up as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p>
</section> </section>
...@@ -3,6 +3,9 @@ ${module_content} ...@@ -3,6 +3,9 @@ ${module_content}
definition = ${definition | h} definition = ${definition | h}
metadata = ${metadata | h} metadata = ${metadata | h}
</div> </div>
%if edit_link:
<div><a href="${edit_link}">Edit</a></div>
% endif
%if render_histogram: %if render_histogram:
<div id="histogram_${element_id}" class="histogram" data-histogram="${histogram}"></div> <div id="histogram_${element_id}" class="histogram" data-histogram="${histogram}"></div>
%endif %endif
...@@ -120,6 +120,22 @@ task :package do ...@@ -120,6 +120,22 @@ task :package do
FileUtils.mkdir_p(BUILD_DIR) FileUtils.mkdir_p(BUILD_DIR)
Dir.chdir(BUILD_DIR) do Dir.chdir(BUILD_DIR) do
afterremove = Tempfile.new('afterremove')
afterremove.write <<-AFTERREMOVE.gsub(/^\s*/, '')
#! /bin/bash
set -e
set -x
# to be a little safer this rm is executed
# as the makeitso user
if [[ -d "#{INSTALL_DIR_PATH}" ]]; then
sudo -u makeitso rm -rf "#{INSTALL_DIR_PATH}"
fi
AFTERREMOVE
afterremove.close()
FileUtils.chmod(0755, afterremove.path)
postinstall = Tempfile.new('postinstall') postinstall = Tempfile.new('postinstall')
postinstall.write <<-POSTINSTALL.gsub(/^\s*/, '') postinstall.write <<-POSTINSTALL.gsub(/^\s*/, '')
...@@ -128,15 +144,12 @@ task :package do ...@@ -128,15 +144,12 @@ task :package do
set -x set -x
chown -R makeitso:makeitso #{INSTALL_DIR_PATH} chown -R makeitso:makeitso #{INSTALL_DIR_PATH}
chmod +x #{INSTALL_DIR_PATH}/collect_static_resources
service gunicorn stop || echo "Unable to stop gunicorn. Continuing" service gunicorn stop || echo "Unable to stop gunicorn. Continuing"
rm -f #{LINK_PATH} rm -f #{LINK_PATH}
ln -s #{INSTALL_DIR_PATH} #{LINK_PATH} ln -s #{INSTALL_DIR_PATH} #{LINK_PATH}
chown makeitso:makeitso #{LINK_PATH} chown makeitso:makeitso #{LINK_PATH}
/opt/wwc/mitx/collect_static_resources
# Delete mako temp files # Delete mako temp files
rm -rf /tmp/tmp*mako rm -rf /tmp/tmp*mako
...@@ -148,6 +161,7 @@ task :package do ...@@ -148,6 +161,7 @@ task :package do
args = ["fakeroot", "fpm", "-s", "dir", "-t", "deb", args = ["fakeroot", "fpm", "-s", "dir", "-t", "deb",
"--verbose", "--verbose",
"--after-install=#{postinstall.path}", "--after-install=#{postinstall.path}",
"--after-remove=#{afterremove.path}",
"--prefix=#{INSTALL_DIR_PATH}", "--prefix=#{INSTALL_DIR_PATH}",
"--exclude=**/build/**", "--exclude=**/build/**",
"--exclude=**/rakefile", "--exclude=**/rakefile",
......
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