From 77f928d118a3c718dd583ec4bf63bef9fad19140 Mon Sep 17 00:00:00 2001 From: kimth Date: Thu, 23 Aug 2012 17:24:59 -0400 Subject: [PATCH] Queuestate records both secret key and time of queue request --- common/lib/capa/capa/capa_problem.py | 6 +----- common/lib/capa/capa/correctmap.py | 11 ++++++----- common/lib/capa/capa/responsetypes.py | 14 ++++++++------ common/lib/xmodule/xmodule/capa_module.py | 6 ++++++ 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index 82eb330174..35c8eaf635 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -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): ''' diff --git a/common/lib/capa/capa/correctmap.py b/common/lib/capa/capa/correctmap.py index eb6ef2d00c..c6fc98e62f 100644 --- a/common/lib/capa/capa/correctmap.py +++ b/common/lib/capa/capa/correctmap.py @@ -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') diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index b2d56b48ca..35b8688a7b 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -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)) diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index d2ed3912a4..6b6c0991c5 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -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