Commit ff5773c0 by ichuang

Merge pull request #348 from MITx/kimth/lms-coderesponse

merging this now because the it looks ok, and it fixes some bugs introduced by the last xserver merge, which are preventing the LMS from running in the current version of master.
parents 24f85bf2 18a7f587
...@@ -29,7 +29,6 @@ import xqueue_interface ...@@ -29,7 +29,6 @@ import xqueue_interface
log = logging.getLogger('mitx.' + __name__) log = logging.getLogger('mitx.' + __name__)
qinterface = xqueue_interface.XqueueInterface()
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# Exceptions # Exceptions
...@@ -811,7 +810,7 @@ class CodeResponse(LoncapaResponse): ...@@ -811,7 +810,7 @@ class CodeResponse(LoncapaResponse):
def setup_response(self): def setup_response(self):
xml = self.xml xml = self.xml
self.queue_name = xml.get('queuename', self.system.xqueue_default_queuename) self.queue_name = xml.get('queuename', self.system.xqueue['default_queuename'])
answer = xml.find('answer') answer = xml.find('answer')
if answer is not None: if answer is not None:
...@@ -859,10 +858,11 @@ class CodeResponse(LoncapaResponse): ...@@ -859,10 +858,11 @@ class CodeResponse(LoncapaResponse):
# Prepare xqueue request # Prepare xqueue request
#------------------------------------------------------------ #------------------------------------------------------------
qinterface = self.system.xqueue['interface']
# Generate header # Generate header
queuekey = xqueue_interface.make_hashkey(self.system.seed) queuekey = xqueue_interface.make_hashkey(str(self.system.seed)+self.answer_id)
xheader = xqueue_interface.make_xheader(lms_callback_url=self.system.xqueue_callback_url, xheader = xqueue_interface.make_xheader(lms_callback_url=self.system.xqueue['callback_url'],
lms_key=queuekey, lms_key=queuekey,
queue_name=self.queue_name) queue_name=self.queue_name)
...@@ -891,7 +891,7 @@ class CodeResponse(LoncapaResponse): ...@@ -891,7 +891,7 @@ class CodeResponse(LoncapaResponse):
msg='Unable to deliver your submission to grader. (Reason: %s.) Please try again later.' % msg) msg='Unable to deliver your submission to grader. (Reason: %s.) Please try again later.' % msg)
else: else:
# Non-null CorrectMap['queuekey'] indicates that the problem has been queued # Non-null CorrectMap['queuekey'] indicates that the problem has been queued
cmap.set(self.answer_id, queuekey=queuekey, msg='Submitted to grader') cmap.set(self.answer_id, queuekey=queuekey, msg='Submitted to grader. (Queue length: %s)' % msg)
return cmap return cmap
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
lineWrapping: true, lineWrapping: true,
indentUnit: "${tabsize}", indentUnit: "${tabsize}",
tabSize: "${tabsize}", tabSize: "${tabsize}",
indentWithTabs: true,
smartIndent: false smartIndent: false
}); });
}); });
...@@ -48,7 +49,7 @@ ...@@ -48,7 +49,7 @@
border: 1px solid black; border: 1px solid black;
font-size: 14px; font-size: 14px;
line-height: 18px; line-height: 18px;
resize: vertical; resize: both;
} }
</style> </style>
</section> </section>
...@@ -47,7 +47,12 @@ def parse_xreply(xreply): ...@@ -47,7 +47,12 @@ def parse_xreply(xreply):
'content': Message from xqueue (string) 'content': Message from xqueue (string)
} }
''' '''
xreply = json.loads(xreply) try:
xreply = json.loads(xreply)
except ValueError, err:
log.error(err)
return (1, 'unexpected reply from server')
return_code = xreply['return_code'] return_code = xreply['return_code']
content = xreply['content'] content = xreply['content']
return (return_code, content) return (return_code, content)
...@@ -61,7 +66,7 @@ class XqueueInterface: ...@@ -61,7 +66,7 @@ class XqueueInterface:
def __init__(self, url=XQUEUE_URL, auth=XQUEUE_LMS_AUTH): def __init__(self, url=XQUEUE_URL, auth=XQUEUE_LMS_AUTH):
self.url = url self.url = url
self.auth = auth self.auth = auth
self.s = requests.session() self.session = requests.session()
self._login() self._login()
def send_to_queue(self, header, body, file_to_upload=None): def send_to_queue(self, header, body, file_to_upload=None):
...@@ -86,29 +91,32 @@ class XqueueInterface: ...@@ -86,29 +91,32 @@ class XqueueInterface:
return (error, msg) return (error, msg)
def _login(self): def _login(self):
try: payload = { 'username': self.auth['username'],
r = self.s.post(self.url+'/xqueue/login/', data={ 'username': self.auth['username'], 'password': self.auth['password'] }
'password': self.auth['password'] }) return self._http_post(self.url+'/xqueue/login/', payload)
except requests.exceptions.ConnectionError, err:
log.error(err)
return (1, 'cannot connect to server')
return parse_xreply(r.text)
def _send_to_queue(self, header, body, file_to_upload=None): def _send_to_queue(self, header, body, file_to_upload=None):
payload = {'xqueue_header': header, payload = {'xqueue_header': header,
'xqueue_body' : body} 'xqueue_body' : body}
files = None files = None
if file_to_upload is not None: if file_to_upload is not None:
files = { file_to_upload.name: file_to_upload } files = { file_to_upload.name: file_to_upload }
return self._http_post(self.url+'/xqueue/submit/', payload, files)
def _http_post(self, url, data, files=None):
try: try:
r = self.s.post(self.url+'/xqueue/submit/', data=payload, files=files) r = self.session.post(url, data=data, files=files)
except requests.exceptions.ConnectionError, err: except requests.exceptions.ConnectionError, err:
log.error(err) log.error(err)
return (1, 'cannot connect to server') return (1, 'cannot connect to server')
if r.status_code not in [200]:
return (1, 'unexpected HTTP status code [%d]' % r.status_code)
return parse_xreply(r.text) return parse_xreply(r.text)
qinterface = XqueueInterface()
...@@ -12,6 +12,7 @@ class @Problem ...@@ -12,6 +12,7 @@ class @Problem
bind: => bind: =>
MathJax.Hub.Queue ["Typeset", MathJax.Hub] MathJax.Hub.Queue ["Typeset", MathJax.Hub]
window.update_schematics() window.update_schematics()
@inputs = @$("[id^=input_#{@element_id.replace(/problem_/, '')}_]")
@$('section.action input:button').click @refreshAnswers @$('section.action input:button').click @refreshAnswers
@$('section.action input.check').click @check_fd @$('section.action input.check').click @check_fd
#@$('section.action input.check').click @check #@$('section.action input.check').click @check
...@@ -66,8 +67,8 @@ class @Problem ...@@ -66,8 +67,8 @@ class @Problem
return return
fd = new FormData() fd = new FormData()
@$("[id^=input_#{@element_id.replace(/problem_/, '')}_]").each (index, element) -> @inputs.each (index, element) ->
if element.type is 'file' if element.type is 'file'
if element.files[0] instanceof File if element.files[0] instanceof File
fd.append(element.id, element.files[0]) fd.append(element.id, element.files[0])
...@@ -155,4 +156,4 @@ class @Problem ...@@ -155,4 +156,4 @@ class @Problem
element.schematic.update_value() element.schematic.update_value()
@$(".CodeMirror").each (index, element) -> @$(".CodeMirror").each (index, element) ->
element.CodeMirror.save() if element.CodeMirror.save element.CodeMirror.save() if element.CodeMirror.save
@answers = @$("[id^=input_#{@element_id.replace(/problem_/, '')}_]").serialize() @answers = @inputs.serialize()
...@@ -643,8 +643,7 @@ class ModuleSystem(object): ...@@ -643,8 +643,7 @@ class ModuleSystem(object):
user=None, user=None,
filestore=None, filestore=None,
debug=False, debug=False,
xqueue_callback_url=None, xqueue = None,
xqueue_default_queuename="null",
is_staff=False): is_staff=False):
''' '''
Create a closure around the system environment. Create a closure around the system environment.
...@@ -668,6 +667,9 @@ class ModuleSystem(object): ...@@ -668,6 +667,9 @@ class ModuleSystem(object):
filestore - A filestore ojbect. Defaults to an instance of OSFS based filestore - A filestore ojbect. Defaults to an instance of OSFS based
at settings.DATA_DIR. at settings.DATA_DIR.
xqueue - Dict containing XqueueInterface object, as well as parameters
for the specific StudentModule
replace_urls - TEMPORARY - A function like static_replace.replace_urls replace_urls - TEMPORARY - A function like static_replace.replace_urls
that capa_module can use to fix up the static urls in that capa_module can use to fix up the static urls in
ajax results. ajax results.
...@@ -676,8 +678,7 @@ class ModuleSystem(object): ...@@ -676,8 +678,7 @@ class ModuleSystem(object):
TODO (vshnayder): this will need to change once we have real user roles. TODO (vshnayder): this will need to change once we have real user roles.
''' '''
self.ajax_url = ajax_url self.ajax_url = ajax_url
self.xqueue_callback_url = xqueue_callback_url self.xqueue = xqueue
self.xqueue_default_queuename = xqueue_default_queuename
self.track_function = track_function self.track_function = track_function
self.filestore = filestore self.filestore = filestore
self.get_module = get_module self.get_module = get_module
......
...@@ -8,6 +8,7 @@ from django.views.decorators.csrf import csrf_exempt ...@@ -8,6 +8,7 @@ from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.models import User from django.contrib.auth.models import User
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from capa.xqueue_interface import qinterface
from mitxmako.shortcuts import render_to_string from mitxmako.shortcuts import render_to_string
from models import StudentModule, StudentModuleCache from models import StudentModule, StudentModuleCache
from static_replace import replace_urls from static_replace import replace_urls
...@@ -157,6 +158,10 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -157,6 +158,10 @@ def get_module(user, request, location, student_module_cache, position=None):
# TODO: Queuename should be derived from 'course_settings.json' of each course # TODO: Queuename should be derived from 'course_settings.json' of each course
xqueue_default_queuename = descriptor.location.org + '-' + descriptor.location.course xqueue_default_queuename = descriptor.location.org + '-' + descriptor.location.course
xqueue = { 'interface': qinterface,
'callback_url': xqueue_callback_url,
'default_queuename': xqueue_default_queuename.replace(' ','_') }
def _get_module(location): def _get_module(location):
(module, _, _, _) = get_module(user, request, location, (module, _, _, _) = get_module(user, request, location,
student_module_cache, position) student_module_cache, position)
...@@ -168,8 +173,7 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -168,8 +173,7 @@ def get_module(user, request, location, student_module_cache, position=None):
system = ModuleSystem(track_function=make_track_function(request), system = ModuleSystem(track_function=make_track_function(request),
render_template=render_to_string, render_template=render_to_string,
ajax_url=ajax_url, ajax_url=ajax_url,
xqueue_callback_url=xqueue_callback_url, xqueue=xqueue,
xqueue_default_queuename=xqueue_default_queuename.replace(' ','_'),
# TODO (cpennington): Figure out how to share info between systems # TODO (cpennington): Figure out how to share info between systems
filestore=descriptor.system.resources_fs, filestore=descriptor.system.resources_fs,
get_module=_get_module, get_module=_get_module,
...@@ -222,6 +226,9 @@ def get_module(user, request, location, student_module_cache, position=None): ...@@ -222,6 +226,9 @@ def get_module(user, request, location, student_module_cache, position=None):
@csrf_exempt @csrf_exempt
def xqueue_callback(request, userid, id, dispatch): def xqueue_callback(request, userid, id, dispatch):
'''
Entry point for graded results from the queueing system.
'''
# Parse xqueue response # Parse xqueue response
get = request.POST.copy() get = request.POST.copy()
try: try:
......
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