diff --git a/common/lib/xmodule/xmodule/js/src/capa/display.coffee b/common/lib/xmodule/xmodule/js/src/capa/display.coffee index 6b39805d1a..c00b680eba 100644 --- a/common/lib/xmodule/xmodule/js/src/capa/display.coffee +++ b/common/lib/xmodule/xmodule/js/src/capa/display.coffee @@ -32,22 +32,37 @@ class @Problem queueing: => @queued_items = @$(".xqueue") - if @queued_items.length > 0 + @num_queued_items = @queued_items.length + if @num_queued_items > 0 if window.queuePollerID # Only one poller 'thread' per Problem window.clearTimeout(window.queuePollerID) - window.queuePollerID = window.setTimeout(@poll, 100) + queuelen = @get_queuelen() + window.queuePollerID = window.setTimeout(@poll, queuelen*10) + # Retrieves the minimum queue length of all queued items + get_queuelen: => + minlen = Infinity + @queued_items.each (index, qitem) -> + len = parseInt($.text(qitem)) + if len < minlen + minlen = len + return minlen + poll: => $.postWithPrefix "#{@url}/problem_get", (response) => - @queued_items = $(response.html).find(".xqueue") - if @queued_items.length == 0 + # If queueing status changed, then render + @new_queued_items = $(response.html).find(".xqueue") + if @new_queued_items.length isnt @num_queued_items @el.html(response.html) @executeProblemScripts () => @setupInputTypes() @bind() + + @num_queued_items = @new_queued_items.length + if @num_queued_items == 0 delete window.queuePollerID else - # TODO: Dynamically adjust timeout interval based on @queued_items.value + # TODO: Some logic to dynamically adjust polling rate based on queuelen window.queuePollerID = window.setTimeout(@poll, 1000) render: (content) -> @@ -141,9 +156,16 @@ class @Problem fd = new FormData() + # Sanity check of file size + file_too_large = false + max_filesize = 4*1000*1000 # 4 MB + @inputs.each (index, element) -> if element.type is 'file' if element.files[0] instanceof File + if element.files[0].size > max_filesize + file_too_large = true + alert 'Submission aborted! Your file "' + element.files[0].name + '" is too large (max size: ' + max_filesize/(1000*1000) + ' MB)' fd.append(element.id, element.files[0]) else fd.append(element.id, '') @@ -163,7 +185,8 @@ class @Problem else alert(response.success) - $.ajaxWithPrefix("#{@url}/problem_check", settings) + if not file_too_large + $.ajaxWithPrefix("#{@url}/problem_check", settings) check: => Logger.log 'problem_check', @answers diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 3bb1c477cb..85eeb72c24 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -336,11 +336,17 @@ def modx_dispatch(request, dispatch=None, id=None, course_id=None): - id -- the module id. Used to look up the XModule instance ''' # ''' (fix emacs broken parsing) - # Check for submitted files + + # Check for submitted files and basic file size checks p = request.POST.copy() if request.FILES: for inputfile_id in request.FILES.keys(): - p[inputfile_id] = request.FILES[inputfile_id] + 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 student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(request.user, modulestore().get_item(id)) instance = get_module(request.user, request, id, student_module_cache) diff --git a/lms/envs/common.py b/lms/envs/common.py index 8ebf72f22a..24a70e3e45 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -128,6 +128,7 @@ TEMPLATE_CONTEXT_PROCESSORS = ( 'django.core.context_processors.csrf', #necessary for csrf protection ) +STUDENT_FILEUPLOAD_MAX_SIZE = 4*1000*1000 # 4 MB # FIXME: # We should have separate S3 staged URLs in case we need to make changes to