From de7d2cd08c4229395ea21025b6c8059d2c736acf Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Thu, 21 Nov 2013 20:40:20 -0500 Subject: [PATCH] Properly convert files from Webob to pure files. Webob represents uploaded files as cgi.FieldStorage objects. The XModule code expects pure Python file objects. Each FieldStorage object is wrapped to present the proper file interface, with file names. LMS-1492 --- .../xmodule/xmodule/tests/test_capa_module.py | 1 - .../xmodule/tests/test_xblock_wrappers.py | 2 +- common/lib/xmodule/xmodule/x_module.py | 27 ++++++++++++++++++- requirements/edx/github.txt | 2 +- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/common/lib/xmodule/xmodule/tests/test_capa_module.py b/common/lib/xmodule/xmodule/tests/test_capa_module.py index ea98c7a249..ce8d7489d5 100644 --- a/common/lib/xmodule/xmodule/tests/test_capa_module.py +++ b/common/lib/xmodule/xmodule/tests/test_capa_module.py @@ -591,7 +591,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 055033a3bb..8618aef9ae 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 @@ -405,7 +406,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