diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index 9db5022209..b7b7d8b6f4 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -590,7 +590,6 @@ class CapaModuleTest(unittest.TestCase): for fpath, fileobj in kwargs['files'].iteritems(): self.assertEqual(fpath, fileobj.name) - @unittest.expectedFailure def test_check_problem_with_files_as_xblock(self): # Check a problem with uploaded files, using the XBlock API. # pylint: disable=W0212 diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py index 258ee5b038..c8ac5fcdd3 100644 --- a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py +++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py @@ -257,7 +257,7 @@ class TestXModuleHandler(TestXBlockWrapper): def setUp(self): self.module = XModule(descriptor=Mock(), field_data=Mock(), runtime=Mock(), scope_ids=Mock()) self.module.handle_ajax = Mock(return_value='{}') - self.request = Mock() + self.request = webob.Request({}) def test_xmodule_handler_passed_data(self): self.module.xmodule_handler(self.request) diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index e644185c8c..cd5a5ef3d9 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -8,6 +8,7 @@ from lxml import etree from collections import namedtuple from pkg_resources import resource_listdir, resource_string, resource_isdir from webob import Response +from webob.multidict import MultiDict from xmodule.modulestore import Location from xmodule.modulestore.exceptions import ItemNotFoundError, InsufficientSpecificationError, InvalidLocationError @@ -406,7 +407,31 @@ class XModule(XModuleMixin, HTMLSnippet, XBlock): # pylint: disable=abstract-me """ XBlock handler that wraps `handle_ajax` """ - response_data = self.handle_ajax(suffix, request.POST) + class FileObjForWebobFiles(object): + """ + Turn Webob cgi.FieldStorage uploaded files into pure file objects. + + Webob represents uploaded files as cgi.FieldStorage objects, which + have a .file attribute. We wrap the FieldStorage object, delegating + attribute access to the .file attribute. But the files have no + name, so we carry the FieldStorage .filename attribute as the .name. + + """ + def __init__(self, webob_file): + self.file = webob_file.file + self.name = webob_file.filename + + def __getattr__(self, name): + return getattr(self.file, name) + + # WebOb requests have multiple entries for uploaded files. handle_ajax + # expects a single entry as a list. + request_post = MultiDict(request.POST) + for key in set(request.POST.iterkeys()): + if hasattr(request.POST[key], "file"): + request_post[key] = map(FileObjForWebobFiles, request.POST.getall(key)) + + response_data = self.handle_ajax(suffix, request_post) return Response(response_data, content_type='application/json') def get_children(self): diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index cf2c528323..26d12f2af9 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -15,7 +15,7 @@ -e git+https://github.com/eventbrite/zendesk.git@d53fe0e81b623f084e91776bcf6369f8b7b63879#egg=zendesk # Our libraries: --e git+https://github.com/edx/XBlock.git@2daa4e54#egg=XBlock +-e git+https://github.com/edx/XBlock.git@d6d2fc91#egg=XBlock -e git+https://github.com/edx/codejail.git@0a1b468#egg=codejail -e git+https://github.com/edx/diff-cover.git@v0.2.6#egg=diff_cover -e git+https://github.com/edx/js-test-tool.git@v0.1.4#egg=js_test_tool