Commit d2cb6458 by kimth

Multiple file submissions

parent d920e718
......@@ -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)
......
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