Merge remote-tracking branch 'origin/master' into MITx/feature/bridger/fast_course_grading
Conflicts: lms/djangoapps/courseware/module_render.py lms/djangoapps/courseware/views.py
This commit is contained in:
@@ -17,6 +17,7 @@ from xmodule.exceptions import NotFoundError
|
||||
from progress import Progress
|
||||
from capa.capa_problem import LoncapaProblem
|
||||
from capa.responsetypes import StudentInputError
|
||||
from capa.util import convert_files_to_filenames
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
|
||||
@@ -425,10 +426,9 @@ class CapaModule(XModule):
|
||||
event_info = dict()
|
||||
event_info['state'] = self.lcp.get_state()
|
||||
event_info['problem_id'] = self.location.url()
|
||||
|
||||
|
||||
answers = self.make_dict_of_responses(get)
|
||||
|
||||
event_info['answers'] = answers
|
||||
event_info['answers'] = convert_files_to_filenames(answers)
|
||||
|
||||
# Too late. Cannot submit
|
||||
if self.closed():
|
||||
@@ -436,8 +436,7 @@ class CapaModule(XModule):
|
||||
self.system.track_function('save_problem_check_fail', event_info)
|
||||
raise NotFoundError('Problem is closed')
|
||||
|
||||
# Problem submitted. Student should reset before checking
|
||||
# again.
|
||||
# Problem submitted. Student should reset before checking again
|
||||
if self.lcp.done and self.rerandomize == "always":
|
||||
event_info['failure'] = 'unreset'
|
||||
self.system.track_function('save_problem_check_fail', event_info)
|
||||
|
||||
@@ -94,7 +94,15 @@ class HtmlDescriptor(XmlDescriptor, EditingDescriptor):
|
||||
msg = "Couldn't parse html in {0}.".format(filepath)
|
||||
log.warning(msg)
|
||||
system.error_tracker("Warning: " + msg)
|
||||
return {'data' : html}
|
||||
|
||||
definition = {'data' : html}
|
||||
|
||||
# TODO (ichuang): remove this after migration
|
||||
# for Fall 2012 LMS migration: keep filename (and unmangled filename)
|
||||
definition['filename'] = [ filepath, filename ]
|
||||
|
||||
return definition
|
||||
|
||||
except (ResourceNotFoundError) as err:
|
||||
msg = 'Unable to load file contents at path {0}: {1} '.format(
|
||||
filepath, err)
|
||||
|
||||
@@ -13,7 +13,8 @@ class @Problem
|
||||
MathJax.Hub.Queue ["Typeset", MathJax.Hub]
|
||||
window.update_schematics()
|
||||
@$('section.action input:button').click @refreshAnswers
|
||||
@$('section.action input.check').click @check
|
||||
@$('section.action input.check').click @check_fd
|
||||
#@$('section.action input.check').click @check
|
||||
@$('section.action input.reset').click @reset
|
||||
@$('section.action input.show').click @show
|
||||
@$('section.action input.save').click @save
|
||||
@@ -45,6 +46,51 @@ class @Problem
|
||||
$('head')[0].appendChild(s[0])
|
||||
$(placeholder).remove()
|
||||
|
||||
###
|
||||
# 'check_fd' uses FormData to allow file submissions in the 'problem_check' dispatch,
|
||||
# in addition to simple querystring-based answers
|
||||
#
|
||||
# NOTE: The dispatch 'problem_check' is being singled out for the use of FormData;
|
||||
# maybe preferable to consolidate all dispatches to use FormData
|
||||
###
|
||||
check_fd: =>
|
||||
Logger.log 'problem_check', @answers
|
||||
|
||||
# If there are no file inputs in the problem, we can fall back on @check
|
||||
if $('input:file').length == 0
|
||||
@check()
|
||||
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."
|
||||
return
|
||||
|
||||
fd = new FormData()
|
||||
|
||||
@$("[id^=input_#{@element_id.replace(/problem_/, '')}_]").each (index, element) ->
|
||||
if element.type is 'file'
|
||||
if element.files[0] instanceof File
|
||||
fd.append(element.id, element.files[0])
|
||||
else
|
||||
fd.append(element.id, '')
|
||||
else
|
||||
fd.append(element.id, element.value)
|
||||
|
||||
settings =
|
||||
type: "POST"
|
||||
data: fd
|
||||
processData: false
|
||||
contentType: false
|
||||
success: (response) =>
|
||||
switch response.success
|
||||
when 'incorrect', 'correct'
|
||||
@render(response.contents)
|
||||
@updateProgress response
|
||||
else
|
||||
alert(response.success)
|
||||
|
||||
$.ajaxWithPrefix("#{@url}/problem_check", settings)
|
||||
|
||||
check: =>
|
||||
Logger.log 'problem_check', @answers
|
||||
$.postWithPrefix "#{@url}/problem_check", @answers, (response) =>
|
||||
|
||||
@@ -146,19 +146,30 @@ class XMLModuleStore(ModuleStoreBase):
|
||||
os.path.exists(self.data_dir / d / "course.xml")]
|
||||
|
||||
for course_dir in course_dirs:
|
||||
try:
|
||||
# Special-case code here, since we don't have a location for the
|
||||
# course before it loads.
|
||||
# So, make a tracker to track load-time errors, then put in the right
|
||||
# place after the course loads and we have its location
|
||||
errorlog = make_error_tracker()
|
||||
course_descriptor = self.load_course(course_dir, errorlog.tracker)
|
||||
self.courses[course_dir] = course_descriptor
|
||||
self._location_errors[course_descriptor.location] = errorlog
|
||||
except:
|
||||
msg = "Failed to load course '%s'" % course_dir
|
||||
log.exception(msg)
|
||||
self.try_load_course(course_dir)
|
||||
|
||||
def try_load_course(self,course_dir):
|
||||
'''
|
||||
Load a course, keeping track of errors as we go along.
|
||||
'''
|
||||
try:
|
||||
# Special-case code here, since we don't have a location for the
|
||||
# course before it loads.
|
||||
# So, make a tracker to track load-time errors, then put in the right
|
||||
# place after the course loads and we have its location
|
||||
errorlog = make_error_tracker()
|
||||
course_descriptor = self.load_course(course_dir, errorlog.tracker)
|
||||
self.courses[course_dir] = course_descriptor
|
||||
self._location_errors[course_descriptor.location] = errorlog
|
||||
except:
|
||||
msg = "Failed to load course '%s'" % course_dir
|
||||
log.exception(msg)
|
||||
|
||||
def __unicode__(self):
|
||||
'''
|
||||
String representation - for debugging
|
||||
'''
|
||||
return '<XMLModuleStore>data_dir=%s, %d courses, %d modules' % (self.data_dir,len(self.courses),len(self.modules))
|
||||
|
||||
def load_course(self, course_dir, tracker):
|
||||
"""
|
||||
|
||||
@@ -204,6 +204,8 @@ class XModule(HTMLSnippet):
|
||||
'''
|
||||
return self.metadata.get('display_name',
|
||||
self.url_name.replace('_', ' '))
|
||||
def __unicode__(self):
|
||||
return '<x_module(name=%s, category=%s, id=%s)>' % (self.name, self.category, self.id)
|
||||
|
||||
def get_children(self):
|
||||
'''
|
||||
|
||||
@@ -41,6 +41,7 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
# to definition_from_xml, and from the xml returned by definition_to_xml
|
||||
metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize',
|
||||
'start', 'due', 'graded', 'display_name', 'url_name', 'hide_from_toc',
|
||||
'ispublic', # if True, then course is listed for all users; see
|
||||
# VS[compat] Remove once unused.
|
||||
'name', 'slug')
|
||||
|
||||
@@ -109,6 +110,7 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
filename = xml_object.get('filename')
|
||||
if filename is None:
|
||||
definition_xml = copy.deepcopy(xml_object)
|
||||
filepath = ''
|
||||
else:
|
||||
filepath = cls._format_filepath(xml_object.tag, filename)
|
||||
|
||||
@@ -136,7 +138,13 @@ class XmlDescriptor(XModuleDescriptor):
|
||||
raise Exception, msg, sys.exc_info()[2]
|
||||
|
||||
cls.clean_metadata_from_xml(definition_xml)
|
||||
return cls.definition_from_xml(definition_xml, system)
|
||||
definition = cls.definition_from_xml(definition_xml, system)
|
||||
|
||||
# TODO (ichuang): remove this after migration
|
||||
# for Fall 2012 LMS migration: keep filename (and unmangled filename)
|
||||
definition['filename'] = [ filepath, filename ]
|
||||
|
||||
return definition
|
||||
|
||||
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user