Queuestate records both secret key and time of queue request
This commit is contained in:
@@ -202,11 +202,7 @@ class LoncapaProblem(object):
|
||||
'''
|
||||
Returns True if any part of the problem has been submitted to an external queue
|
||||
'''
|
||||
queued = False
|
||||
for answer_id in self.correct_map:
|
||||
if self.correct_map.is_queued(answer_id):
|
||||
queued = True
|
||||
return queued
|
||||
return any([self.correct_map.is_queued(answer_id) for answer_id in self.correct_map])
|
||||
|
||||
def grade_answers(self, answers):
|
||||
'''
|
||||
|
||||
@@ -15,7 +15,8 @@ class CorrectMap(object):
|
||||
- msg : string (may have HTML) giving extra message response (displayed below textline or textbox)
|
||||
- hint : string (may have HTML) giving optional hint (displayed below textline or textbox, above msg)
|
||||
- hintmode : one of (None,'on_request','always') criteria for displaying hint
|
||||
- queuekey : a random integer for xqueue_callback verification
|
||||
- queuestate : Tuple (key, time) where key is a secret string, and time is a string dump
|
||||
of a DateTime object in the format '%Y%m%d%H%M%S'. Is None when not queued
|
||||
|
||||
Behaves as a dict.
|
||||
'''
|
||||
@@ -31,14 +32,14 @@ class CorrectMap(object):
|
||||
def __iter__(self):
|
||||
return self.cmap.__iter__()
|
||||
|
||||
def set(self, answer_id=None, correctness=None, npoints=None, msg='', hint='', hintmode=None, queuekey=None):
|
||||
def set(self, answer_id=None, correctness=None, npoints=None, msg='', hint='', hintmode=None, queuestate=None):
|
||||
if answer_id is not None:
|
||||
self.cmap[answer_id] = {'correctness': correctness,
|
||||
'npoints': npoints,
|
||||
'msg': msg,
|
||||
'hint': hint,
|
||||
'hintmode': hintmode,
|
||||
'queuekey': queuekey,
|
||||
'queuestate': queuestate,
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
@@ -67,10 +68,10 @@ class CorrectMap(object):
|
||||
return None
|
||||
|
||||
def is_queued(self, answer_id):
|
||||
return answer_id in self.cmap and self.cmap[answer_id]['queuekey'] is not None
|
||||
return answer_id in self.cmap and self.cmap[answer_id]['queuestate'] is not None
|
||||
|
||||
def is_right_queuekey(self, answer_id, test_key):
|
||||
return answer_id in self.cmap and self.cmap[answer_id]['queuekey'] == test_key
|
||||
return self.is_queued(answer_id) and self.cmap[answer_id]['queuestate'][0] == test_key
|
||||
|
||||
def get_npoints(self, answer_id):
|
||||
npoints = self.get_property(answer_id, 'npoints')
|
||||
|
||||
@@ -26,6 +26,7 @@ import xml.sax.saxutils as saxutils
|
||||
# specific library imports
|
||||
from calc import evaluator, UndefinedVariable
|
||||
from correctmap import CorrectMap
|
||||
from datetime import datetime
|
||||
from util import *
|
||||
from lxml import etree
|
||||
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
|
||||
@@ -1026,7 +1027,7 @@ class CodeResponse(LoncapaResponse):
|
||||
TODO: Determines whether in synchronous or asynchronous (queued) mode
|
||||
'''
|
||||
xml = self.xml
|
||||
self.url = xml.get('url', None) # XML can override external resource (grader/queue) URL
|
||||
self.url = xml.get('url', None) # TODO: XML can override external resource (grader/queue) URL
|
||||
self.queue_name = xml.get('queuename', self.system.xqueue['default_queuename'])
|
||||
|
||||
# VS[compat]:
|
||||
@@ -1128,7 +1129,7 @@ class CodeResponse(LoncapaResponse):
|
||||
xheader = xqueue_interface.make_xheader(lms_callback_url=self.system.xqueue['callback_url'],
|
||||
lms_key=queuekey,
|
||||
queue_name=self.queue_name)
|
||||
|
||||
|
||||
# Generate body
|
||||
if is_list_of_files(submission):
|
||||
self.context.update({'submission': queuekey}) # For tracking. TODO: May want to record something else here
|
||||
@@ -1148,16 +1149,17 @@ class CodeResponse(LoncapaResponse):
|
||||
(error, msg) = qinterface.send_to_queue(header=xheader,
|
||||
body=json.dumps(contents))
|
||||
|
||||
queuestate = (queuekey,'')
|
||||
cmap = CorrectMap()
|
||||
if error:
|
||||
cmap.set(self.answer_id, queuekey=None,
|
||||
cmap.set(self.answer_id, queuestate=None,
|
||||
msg='Unable to deliver your submission to grader. (Reason: %s.) Please try again later.' % msg)
|
||||
else:
|
||||
# Queueing mechanism flags:
|
||||
# 1) Backend: Non-null CorrectMap['queuekey'] indicates that the problem has been queued
|
||||
# 1) Backend: Non-null CorrectMap['queuestate'] indicates that the problem has been queued
|
||||
# 2) Frontend: correctness='incomplete' eventually trickles down through inputtypes.textbox
|
||||
# and .filesubmission to inform the browser to poll the LMS
|
||||
cmap.set(self.answer_id, queuekey=queuekey, correctness='incomplete', msg=msg)
|
||||
cmap.set(self.answer_id, queuestate=queuestate, correctness='incomplete', msg=msg)
|
||||
|
||||
return cmap
|
||||
|
||||
@@ -1180,7 +1182,7 @@ class CodeResponse(LoncapaResponse):
|
||||
points = 0
|
||||
elif points > self.maxpoints[self.answer_id]:
|
||||
points = self.maxpoints[self.answer_id]
|
||||
oldcmap.set(self.answer_id, npoints=points, correctness=correctness, msg=msg.replace(' ', ' '), queuekey=None) # Queuekey is consumed
|
||||
oldcmap.set(self.answer_id, npoints=points, correctness=correctness, msg=msg.replace(' ', ' '), queuestate=None) # Queuestate is consumed
|
||||
else:
|
||||
log.debug('CodeResponse: queuekey %s does not match for answer_id=%s.' % (queuekey, self.answer_id))
|
||||
|
||||
|
||||
@@ -462,6 +462,12 @@ class CapaModule(XModule):
|
||||
self.system.track_function('save_problem_check_fail', event_info)
|
||||
raise NotFoundError('Problem must be reset before it can be checked again')
|
||||
|
||||
# Problem queued. Student should not be able to submit
|
||||
'''
|
||||
if self.lcp.is_queued():
|
||||
return {'success': False, 'html': 'Already queued'}
|
||||
'''
|
||||
|
||||
try:
|
||||
old_state = self.lcp.get_state()
|
||||
lcp_id = self.lcp.problem_id
|
||||
|
||||
Reference in New Issue
Block a user