diff --git a/cms/djangoapps/contentstore/views/import_export.py b/cms/djangoapps/contentstore/views/import_export.py index 839005ceb9..55af032318 100644 --- a/cms/djangoapps/contentstore/views/import_export.py +++ b/cms/djangoapps/contentstore/views/import_export.py @@ -27,6 +27,7 @@ from opaque_keys.edx.locator import LibraryLocator from path import Path as path from six import text_type from storages.backends.s3boto import S3BotoStorage +from storages.backends.s3boto3 import S3Boto3Storage from user_tasks.conf import settings as user_tasks_settings from user_tasks.models import UserTaskArtifact, UserTaskStatus @@ -382,6 +383,14 @@ def export_status_handler(request, course_key_string): 'response-content-encoding': 'application/octet-stream', 'response-content-type': 'application/x-tgz' }) + elif isinstance(artifact.file.storage, S3Boto3Storage): + filename = os.path.basename(artifact.file.name) + disposition = u'attachment; filename="{}"'.format(filename) + output_url = artifact.file.storage.url(artifact.file.name, parameters={ + 'ResponseContentDisposition': disposition, + 'ResponseContentEncoding': 'application/octet-stream', + 'ResponseContentType': 'application/x-tgz' + }) else: output_url = artifact.file.storage.url(artifact.file.name) elif task_status.state in (UserTaskStatus.FAILED, UserTaskStatus.CANCELED): diff --git a/cms/djangoapps/contentstore/views/tests/test_import_export.py b/cms/djangoapps/contentstore/views/tests/test_import_export.py index 75ad02cc69..0d1d637529 100644 --- a/cms/djangoapps/contentstore/views/tests/test_import_export.py +++ b/cms/djangoapps/contentstore/views/tests/test_import_export.py @@ -24,6 +24,7 @@ from opaque_keys.edx.locator import LibraryLocator from path import Path as path from six.moves import zip from storages.backends.s3boto import S3BotoStorage +from storages.backends.s3boto3 import S3Boto3Storage from user_tasks.models import UserTaskStatus from cms.djangoapps.contentstore.tests.test_libraries import LibraryTestCase @@ -805,10 +806,12 @@ class ExportTestCase(CourseTestCase): result = json.loads(resp.content.decode('utf-8')) self.assertEqual(result['ExportOutput'], '/path/to/testfile.tar.gz') + @ddt.data(S3BotoStorage, S3Boto3Storage) @patch('cms.djangoapps.contentstore.views.import_export._latest_task_status') @patch('user_tasks.models.UserTaskArtifact.objects.get') def test_export_status_handler_s3( self, + s3_storage, mock_get_user_task_artifact, mock_latest_task_status, ): @@ -818,7 +821,7 @@ class ExportTestCase(CourseTestCase): """ mock_latest_task_status.return_value = Mock(state=UserTaskStatus.SUCCEEDED) mock_get_user_task_artifact.return_value = self._mock_artifact( - spec=S3BotoStorage, + spec=s3_storage, file_url='/s3/file/path/testfile.tar.gz', ) resp = self.client.get(self.status_url)