def test_error_conditions(self): """ Verifies that exceptions are thrown in the expected cases. """ with self.assertRaises(ValueError) as error: self.request.FILES = {"uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content)} store_uploaded_file(self.request, "wrong_key", [".txt", ".csv"], "stored_file", self.default_max_size) self.verify_exception("No file uploaded with key 'wrong_key'.", error) with self.assertRaises(exceptions.PermissionDenied) as error: self.request.FILES = {"uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content)} store_uploaded_file(self.request, "uploaded_file", [], "stored_file", self.default_max_size) self.verify_exception("The file must end with one of the following extensions: ''.", error) with self.assertRaises(exceptions.PermissionDenied) as error: self.request.FILES = {"uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content)} store_uploaded_file(self.request, "uploaded_file", [".bar"], "stored_file", self.default_max_size) self.verify_exception("The file must end with the extension '.bar'.", error) with self.assertRaises(exceptions.PermissionDenied) as error: self.request.FILES = {"uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content)} store_uploaded_file(self.request, "uploaded_file", [".xxx", ".bar"], "stored_file", self.default_max_size) self.verify_exception("The file must end with one of the following extensions: '.xxx', '.bar'.", error) with self.assertRaises(exceptions.PermissionDenied) as error: self.request.FILES = {"uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content)} store_uploaded_file(self.request, "uploaded_file", [".csv"], "stored_file", 2) self.verify_exception("Maximum upload file size is 2 bytes.", error)
def test_validator(self): """ Verify that a validator function can throw an exception. """ validator_data = {} def verify_file_presence(should_exist): """ Verify whether or not the stored file, passed to the validator, exists. """ self.assertEqual( should_exist, validator_data["storage"].exists(validator_data["filename"])) def store_file_data(storage, filename): """ Stores file validator data for testing after validation is complete. """ validator_data["storage"] = storage validator_data["filename"] = filename verify_file_presence(True) def exception_validator(storage, filename): """ Validation test function that throws an exception """ self.assertEqual("error_file.csv", os.path.basename(filename)) with storage.open(filename, 'rb') as f: self.assertEqual(self.file_content, f.read()) store_file_data(storage, filename) raise FileValidationException("validation failed") def success_validator(storage, filename): """ Validation test function that is a no-op """ self.assertIn("success_file", os.path.basename(filename)) store_file_data(storage, filename) with self.assertRaises(FileValidationException) as error: self.request.FILES = { "uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content) } store_uploaded_file(self.request, "uploaded_file", [".csv"], "error_file", self.default_max_size, validator=exception_validator) self.verify_exception("validation failed", error) # Verify the file was deleted. verify_file_presence(False) self.request.FILES = { "uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content) } store_uploaded_file(self.request, "uploaded_file", [".csv"], "success_file", self.default_max_size, validator=success_validator) # Verify the file still exists verify_file_presence(True)
def post(self, request, course_id): """ Handles a file upload. """ thread_key = request.POST.get("thread_key", "root") unique_file_name = f"{course_id}/{thread_key}/{uuid.uuid4()}" try: file_storage, stored_file_name = store_uploaded_file( request, "uploaded_file", cc_settings.ALLOWED_UPLOAD_FILE_TYPES, unique_file_name, max_file_size=cc_settings.MAX_UPLOAD_FILE_SIZE, ) except ValueError as err: raise BadRequest("no `uploaded_file` was provided") from err file_absolute_url = file_storage.url(stored_file_name) # this is a no-op in production, but is required in development, # since the filesystem storage returns the path without a base_url file_absolute_url = request.build_absolute_uri(file_absolute_url) return Response( {"location": file_absolute_url}, content_type="application/json", )
def upload(request, course_id): # ajax upload file to a question or answer # lint-amnesty, pylint: disable=unused-argument """view that handles file upload via Ajax """ # check upload permission error = '' new_file_name = '' try: # TODO authorization #may raise exceptions.PermissionDenied #if request.user.is_anonymous: # msg = _('Sorry, anonymous users cannot upload files') # raise exceptions.PermissionDenied(msg) #request.user.assert_can_upload_file() base_file_name = str(time.time()).replace( '.', str(random.randint(0, 100000))) file_storage, new_file_name = store_uploaded_file( request, 'file-upload', cc_settings.ALLOWED_UPLOAD_FILE_TYPES, base_file_name, max_file_size=cc_settings.MAX_UPLOAD_FILE_SIZE) except exceptions.PermissionDenied as err: error = str(err) except Exception as err: # pylint: disable=broad-except print(err) logging.critical(str(err)) error = _( 'Error uploading file. Please contact the site administrator. Thank you.' ) if error == '': result = _('Good') file_url = file_storage.url(new_file_name) parsed_url = six.moves.urllib.parse.urlparse(file_url) file_url = six.moves.urllib.parse.urlunparse( six.moves.urllib.parse.ParseResult(parsed_url.scheme, parsed_url.netloc, parsed_url.path, '', '', '')) else: result = '' file_url = '' # Using content-type of text/plain here instead of JSON because # IE doesn't know how to handle the JSON response and prompts the # user to save the JSON as a file instead of passing it to the callback. return HttpResponse( json.dumps({ # lint-amnesty, pylint: disable=http-response-with-json-dumps 'result': { 'msg': result, 'error': error, 'file_url': file_url, } }), content_type="text/plain")
def test_file_upload_lower_case_extension(self): """ Tests uploading a file with lower case extension. Verifies that the stored file contents are correct. """ self.request.FILES = {"uploaded_file": SimpleUploadedFile("tempfile.csv", self.file_content)} file_storage, stored_file_name = store_uploaded_file( self.request, "uploaded_file", [".csv"], "stored_file", self.default_max_size ) self._verify_successful_upload(file_storage, stored_file_name, self.file_content)
def test_unique_filenames(self): """ Test that the file storage method will create a unique filename if the file already exists. """ requested_file_name = "nonunique_store" file_content = b"copy" self.request.FILES = {"nonunique_file": SimpleUploadedFile("nonunique.txt", file_content)} _, first_stored_file_name = store_uploaded_file( self.request, "nonunique_file", [".txt"], requested_file_name, self.default_max_size ) self.request.FILES = {"nonunique_file": SimpleUploadedFile("nonunique.txt", file_content)} file_storage, second_stored_file_name = store_uploaded_file( self.request, "nonunique_file", [".txt"], requested_file_name, self.default_max_size ) self.assertNotEqual(first_stored_file_name, second_stored_file_name) self.assertIn(requested_file_name, second_stored_file_name) self._verify_successful_upload(file_storage, second_stored_file_name, file_content)