Multiple file submissions
This commit is contained in:
@@ -1119,11 +1119,6 @@ class CodeResponse(LoncapaResponse):
|
||||
(err, self.answer_id, convert_files_to_filenames(student_answers)))
|
||||
raise Exception(err)
|
||||
|
||||
if is_file(submission):
|
||||
self.context.update({'submission': submission.name})
|
||||
else:
|
||||
self.context.update({'submission': submission})
|
||||
|
||||
# Prepare xqueue request
|
||||
#------------------------------------------------------------
|
||||
qinterface = self.system.xqueue['interface']
|
||||
@@ -1135,14 +1130,19 @@ class CodeResponse(LoncapaResponse):
|
||||
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
|
||||
else:
|
||||
self.context.update({'submission': submission})
|
||||
|
||||
contents = self.payload.copy()
|
||||
|
||||
# Submit request. When successful, 'msg' is the prior length of the queue
|
||||
if is_file(submission):
|
||||
contents.update({'student_response': submission.name})
|
||||
if is_list_of_files(submission):
|
||||
contents.update({'student_response': ''}) # TODO: Is there any information we want to send here?
|
||||
(error, msg) = qinterface.send_to_queue(header=xheader,
|
||||
body=json.dumps(contents),
|
||||
file_to_upload=submission)
|
||||
files_to_upload=submission)
|
||||
else:
|
||||
contents.update({'student_response': submission})
|
||||
(error, msg) = qinterface.send_to_queue(header=xheader,
|
||||
|
||||
@@ -39,12 +39,26 @@ def convert_files_to_filenames(answers):
|
||||
'''
|
||||
new_answers = dict()
|
||||
for answer_id in answers.keys():
|
||||
if is_file(answers[answer_id]):
|
||||
new_answers[answer_id] = answers[answer_id].name
|
||||
answer = answers[answer_id]
|
||||
if is_list_of_files(answer): # Files are stored as a list, even if one file
|
||||
list_of_filenames = []
|
||||
for inputfile in answer:
|
||||
list_of_filenames.append(inputfile.name)
|
||||
new_answers[answer_id] = list_of_filenames
|
||||
else:
|
||||
new_answers[answer_id] = answers[answer_id]
|
||||
return new_answers
|
||||
|
||||
def is_list_of_files(list_of_files_to_test):
|
||||
if not isinstance(list_of_files_to_test, list):
|
||||
return False
|
||||
|
||||
for li in list_of_files_to_test:
|
||||
if not is_file(li):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def is_file(file_to_test):
|
||||
'''
|
||||
Duck typing to check if 'file_to_test' is a File object
|
||||
|
||||
@@ -65,7 +65,7 @@ class XQueueInterface(object):
|
||||
self.auth = django_auth
|
||||
self.session = requests.session(auth=requests_auth)
|
||||
|
||||
def send_to_queue(self, header, body, file_to_upload=None):
|
||||
def send_to_queue(self, header, body, files_to_upload=[]):
|
||||
'''
|
||||
Submit a request to xqueue.
|
||||
|
||||
@@ -74,16 +74,16 @@ class XQueueInterface(object):
|
||||
body: Serialized data for the receipient behind the queueing service. The operation of
|
||||
xqueue is agnostic to the contents of 'body'
|
||||
|
||||
file_to_upload: File object to be uploaded to xqueue along with queue request
|
||||
files_to_upload: List of file objects to be uploaded to xqueue along with queue request
|
||||
|
||||
Returns (error_code, msg) where error_code != 0 indicates an error
|
||||
'''
|
||||
# Attempt to send to queue
|
||||
(error, msg) = self._send_to_queue(header, body, file_to_upload)
|
||||
(error, msg) = self._send_to_queue(header, body, files_to_upload)
|
||||
|
||||
if error and (msg == 'login_required'): # Log in, then try again
|
||||
self._login()
|
||||
(error, msg) = self._send_to_queue(header, body, file_to_upload)
|
||||
(error, msg) = self._send_to_queue(header, body, files_to_upload)
|
||||
|
||||
return (error, msg)
|
||||
|
||||
@@ -94,12 +94,13 @@ class XQueueInterface(object):
|
||||
return self._http_post(self.url+'/xqueue/login/', payload)
|
||||
|
||||
|
||||
def _send_to_queue(self, header, body, file_to_upload=None):
|
||||
def _send_to_queue(self, header, body, files_to_upload):
|
||||
payload = {'xqueue_header': header,
|
||||
'xqueue_body' : body}
|
||||
files = None
|
||||
if file_to_upload is not None:
|
||||
files = { file_to_upload.name: file_to_upload }
|
||||
for f in files_to_upload:
|
||||
files = { f.name: f }
|
||||
|
||||
return self._http_post(self.url+'/xqueue/submit/', payload, files)
|
||||
|
||||
|
||||
|
||||
@@ -151,28 +151,33 @@ class @Problem
|
||||
return
|
||||
|
||||
if not window.FormData
|
||||
alert "Sorry, your browser does not support file uploads. Your submit request could not be fulfilled. If you can, please use Chrome or Safari which have been verified to support file uploads."
|
||||
alert "Submission aborted! Sorry, your browser does not support file uploads. If you can, please use Chrome or Safari which have been verified to support file uploads."
|
||||
return
|
||||
|
||||
fd = new FormData()
|
||||
|
||||
# Sanity check of file size
|
||||
abort_submission = false
|
||||
# Sanity checks on submission
|
||||
max_filesize = 4*1000*1000 # 4 MB
|
||||
file_too_large = false
|
||||
file_not_selected = false
|
||||
|
||||
@inputs.each (index, element) ->
|
||||
if element.type is 'file'
|
||||
for file in element.files
|
||||
if file.size > max_filesize
|
||||
abort_submission = true
|
||||
file_too_large = true
|
||||
alert 'Submission aborted! Your file "' + file.name '" is too large (max size: ' + max_filesize/(1000*1000) + ' MB)'
|
||||
fd.append(element.id, file)
|
||||
if element.files.length == 0
|
||||
abort_submission = true
|
||||
alert 'Submission aborted! You did not select any files to submit'
|
||||
fd.append(element.id, '')
|
||||
file_not_selected = true
|
||||
fd.append(element.id, '') # In case we want to allow submissions with no file
|
||||
else
|
||||
fd.append(element.id, element.value)
|
||||
|
||||
if file_not_selected
|
||||
alert 'Submission aborted! You did not select any files to submit'
|
||||
|
||||
abort_submission = file_too_large or file_not_selected
|
||||
|
||||
settings =
|
||||
type: "POST"
|
||||
@@ -186,7 +191,7 @@ class @Problem
|
||||
@updateProgress response
|
||||
else
|
||||
alert(response.success)
|
||||
|
||||
|
||||
if not abort_submission
|
||||
$.ajaxWithPrefix("#{@url}/problem_check", settings)
|
||||
|
||||
|
||||
@@ -375,15 +375,16 @@ def modx_dispatch(request, dispatch=None, id=None, course_id=None):
|
||||
# ''' (fix emacs broken parsing)
|
||||
|
||||
# Check for submitted files and basic file size checks
|
||||
p = request.POST.copy()
|
||||
p = request.POST.dict()
|
||||
if request.FILES:
|
||||
for inputfile_id in request.FILES.keys():
|
||||
inputfile = request.FILES[inputfile_id]
|
||||
if inputfile.size > settings.STUDENT_FILEUPLOAD_MAX_SIZE: # Bytes
|
||||
file_too_big_msg = 'Submission aborted! Your file "%s" is too large (max size: %d MB)' %\
|
||||
(inputfile.name, settings.STUDENT_FILEUPLOAD_MAX_SIZE/(1000**2))
|
||||
return HttpResponse(json.dumps({'success': file_too_big_msg}))
|
||||
p[inputfile_id] = inputfile
|
||||
for fileinput_id in request.FILES.keys():
|
||||
inputfiles = request.FILES.getlist(fileinput_id)
|
||||
for inputfile in inputfiles:
|
||||
if inputfile.size > settings.STUDENT_FILEUPLOAD_MAX_SIZE: # Bytes
|
||||
file_too_big_msg = 'Submission aborted! Your file "%s" is too large (max size: %d MB)' %\
|
||||
(inputfile.name, settings.STUDENT_FILEUPLOAD_MAX_SIZE/(1000**2))
|
||||
return HttpResponse(json.dumps({'success': file_too_big_msg}))
|
||||
p[fileinput_id] = inputfiles
|
||||
|
||||
student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(request.user, modulestore().get_item(id))
|
||||
instance = get_module(request.user, request, id, student_module_cache, course_id=course_id)
|
||||
|
||||
Reference in New Issue
Block a user