Commit 7b3c4945 by Julian Arni

Review fixes

Studio: revises import help/status copy to better reflect/generalize what is done with imported content

Add test cases for import status
parent 642bf0e6
...@@ -6,11 +6,17 @@ import shutil ...@@ -6,11 +6,17 @@ import shutil
import tarfile import tarfile
import tempfile import tempfile
import copy import copy
<<<<<<< HEAD
from path import path from path import path
=======
import json
import logging
>>>>>>> Review fixes
from uuid import uuid4 from uuid import uuid4
from pymongo import MongoClient from pymongo import MongoClient
from .utils import CourseTestCase from .utils import CourseTestCase
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.test.utils import override_settings from django.test.utils import override_settings
from django.conf import settings from django.conf import settings
...@@ -20,6 +26,10 @@ from xmodule.contentstore.django import _CONTENTSTORE ...@@ -20,6 +26,10 @@ from xmodule.contentstore.django import _CONTENTSTORE
TEST_DATA_CONTENTSTORE = copy.deepcopy(settings.CONTENTSTORE) TEST_DATA_CONTENTSTORE = copy.deepcopy(settings.CONTENTSTORE)
TEST_DATA_CONTENTSTORE['OPTIONS']['db'] = 'test_xcontent_%s' % uuid4().hex TEST_DATA_CONTENTSTORE['OPTIONS']['db'] = 'test_xcontent_%s' % uuid4().hex
<<<<<<< HEAD
=======
log = logging.getLogger(__name__)
>>>>>>> Review fixes
@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE) @override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE)
class ImportTestCase(CourseTestCase): class ImportTestCase(CourseTestCase):
...@@ -84,6 +94,17 @@ class ImportTestCase(CourseTestCase): ...@@ -84,6 +94,17 @@ class ImportTestCase(CourseTestCase):
"course-data": [btar] "course-data": [btar]
}) })
self.assertEquals(resp.status_code, 415) self.assertEquals(resp.status_code, 415)
# Check that `import_status` returns the appropriate stage (i.e., the
# stage at which import failed).
status_url = reverse("import_status", kwargs={
'org': self.course.location.org,
'course': self.course.location.course,
'name': os.path.split(self.bad_tar)[1],
})
resp_status = self.client.get(status_url)
log.debug(str(self.client.session["import_status"]))
self.assertEquals(json.loads(resp_status.content)["ImportStatus"], 2)
def test_with_coursexml(self): def test_with_coursexml(self):
""" """
...@@ -183,3 +204,14 @@ class ImportTestCase(CourseTestCase): ...@@ -183,3 +204,14 @@ class ImportTestCase(CourseTestCase):
try_tar(self._symlink_tar()) try_tar(self._symlink_tar())
try_tar(self._outside_tar()) try_tar(self._outside_tar())
try_tar(self._outside_tar2()) try_tar(self._outside_tar2())
# Check that `import_status` returns the appropriate stage (i.e.,
# either 3, indicating all previous steps are completed, or 0,
# indicating no upload in progress)
status_url = reverse("import_status", kwargs={
'org': self.course.location.org,
'course': self.course.location.course,
'name': os.path.split(self.good_tar)[1],
})
resp_status = self.client.get(status_url)
import_status = json.loads(resp_status.content)["ImportStatus"]
self.assertTrue(import_status == 3 or import_status == 0)
...@@ -9,7 +9,6 @@ import shutil ...@@ -9,7 +9,6 @@ import shutil
import re import re
from tempfile import mkdtemp from tempfile import mkdtemp
from path import path from path import path
from contextlib import contextmanager
from django.conf import settings from django.conf import settings
from django.http import HttpResponse from django.http import HttpResponse
...@@ -20,6 +19,7 @@ from django.core.servers.basehttp import FileWrapper ...@@ -20,6 +19,7 @@ from django.core.servers.basehttp import FileWrapper
from django.core.files.temp import NamedTemporaryFile from django.core.files.temp import NamedTemporaryFile
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
from django.views.decorators.http import require_http_methods, require_GET from django.views.decorators.http import require_http_methods, require_GET
from django.utils.translation import ugettext as _
from mitxmako.shortcuts import render_to_response from mitxmako.shortcuts import render_to_response
from auth.authz import create_all_course_groups from auth.authz import create_all_course_groups
...@@ -65,7 +65,7 @@ def import_course(request, org, course, name): ...@@ -65,7 +65,7 @@ def import_course(request, org, course, name):
if not filename.endswith('.tar.gz'): if not filename.endswith('.tar.gz'):
return JsonResponse( return JsonResponse(
{ {
'ErrMsg': 'We only support uploading a .tar.gz file.', 'ErrMsg': _('We only support uploading a .tar.gz file.'),
'Stage': 1 'Stage': 1
}, },
status=415 status=415
...@@ -102,7 +102,7 @@ def import_course(request, org, course, name): ...@@ -102,7 +102,7 @@ def import_course(request, org, course, name):
) )
return JsonResponse( return JsonResponse(
{ {
'ErrMsg': 'File upload corrupted. Please try again', 'ErrMsg': _('File upload corrupted. Please try again'),
'Stage': 1 'Stage': 1
}, },
status=409 status=409
...@@ -163,8 +163,6 @@ def import_course(request, org, course, name): ...@@ -163,8 +163,6 @@ def import_course(request, org, course, name):
request.session.modified = True request.session.modified = True
# find the 'course.xml' file # find the 'course.xml' file
dirpath = None
def get_all_files(directory): def get_all_files(directory):
""" """
For each file in the directory, yield a 2-tuple of (file-name, For each file in the directory, yield a 2-tuple of (file-name,
...@@ -192,7 +190,7 @@ def import_course(request, org, course, name): ...@@ -192,7 +190,7 @@ def import_course(request, org, course, name):
if not dirpath: if not dirpath:
return JsonResponse( return JsonResponse(
{ {
'ErrMsg': 'Could not find the course.xml file in the package.', 'ErrMsg': _('Could not find the course.xml file in the package.'),
'Stage': 2 'Stage': 2
}, },
status=415 status=415
...@@ -223,7 +221,7 @@ def import_course(request, org, course, name): ...@@ -223,7 +221,7 @@ def import_course(request, org, course, name):
logging.debug('created all course groups at {0}'.format(course_items[0].location)) logging.debug('created all course groups at {0}'.format(course_items[0].location))
# Send errors to client with stage at which error occured. # Send errors to client with stage at which error occured.
except Exception as exception: #pylint: disable=W0703 except Exception as exception: # pylint: disable=W0703
return JsonResponse( return JsonResponse(
{ {
'ErrMsg': str(exception), 'ErrMsg': str(exception),
...@@ -248,6 +246,7 @@ def import_course(request, org, course, name): ...@@ -248,6 +246,7 @@ def import_course(request, org, course, name):
}) })
}) })
@require_GET @require_GET
@ensure_csrf_cookie @ensure_csrf_cookie
@login_required @login_required
...@@ -268,7 +267,7 @@ def import_status(request, org, course, name): ...@@ -268,7 +267,7 @@ def import_status(request, org, course, name):
except KeyError: except KeyError:
status = 0 status = 0
return JsonResponse({"ImportStatus": status }) return JsonResponse({"ImportStatus": status})
@ensure_csrf_cookie @ensure_csrf_cookie
...@@ -349,6 +348,7 @@ def generate_export_course(request, org, course, name): ...@@ -349,6 +348,7 @@ def generate_export_course(request, org, course, name):
response['Content-Length'] = os.path.getsize(export_file.name) response['Content-Length'] = os.path.getsize(export_file.name)
return response return response
@ensure_csrf_cookie @ensure_csrf_cookie
@login_required @login_required
def export_course(request, org, course, name): def export_course(request, org, course, name):
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
<div class="introduction"> <div class="introduction">
<p>${_("You may import existing course structure and content into Studio.")}</p> <p>${_("You may import existing course structure and content into Studio.")}</p>
<p>${_("Importing is not something to take lightly as the course content you successfully upload will replace your current content and cannot be reversed. Please be certain you want to replace your course's content.")}</p> <p>${_("Importing is not something to take lightly as the course content you successfully upload will be integrated into your course content and cannot be reversed.")}</p>
<p>${_("During the import process, please do not navigate away from this page.")}</p> <p>${_("During the initial stages of the import process, please do not navigate away from this page.")}</p>
</div> </div>
<form id="fileupload" method="post" enctype="multipart/form-data" <form id="fileupload" method="post" enctype="multipart/form-data"
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
<div class="status-detail"> <div class="status-detail">
<h3 class="title">${_("Updating Course")}</h3> <h3 class="title">${_("Updating Course")}</h3>
<p class="copy">${_("Replacing previous course content with imported content. This may take a while with larger courses.")}</p> <p class="copy">${_("Integrating your imported content into this course. This may take a while with larger courses.")}</p>
</div> </div>
</li> </li>
<li class="item-progresspoint item-progresspoint-success has-actions is-not-started"> <li class="item-progresspoint item-progresspoint-success has-actions is-not-started">
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
<div class="status-detail"> <div class="status-detail">
<h3 class="title">${_("Success")}</h3> <h3 class="title">${_("Success")}</h3>
<p class="copy">${_("Your imported content has now replaced all other course content")}</p> <p class="copy">${_("Your imported content has now been integrated into this course")}</p>
</div> </div>
<ul class="list-actions"> <ul class="list-actions">
...@@ -125,11 +125,6 @@ ...@@ -125,11 +125,6 @@
<aside class="content-supplementary" role="complimentary"> <aside class="content-supplementary" role="complimentary">
<div class="bit"> <div class="bit">
<h3 class="title-3">${_("Current Content & Importing")}</h3>
<p>${_("Importing a new course will delete all content currently associated with your course and replace it with the contents of the uploaded file.")}</p>
</div>
<div class="bit">
<h3 class="title-3">${_("Gzipped Tar Files (.tar.gz) Only")}</h3> <h3 class="title-3">${_("Gzipped Tar Files (.tar.gz) Only")}</h3>
## Translators: ".tar.gz" is a file extension, and files with that extension are called "gzipped tar files": these terms should not be translated ## Translators: ".tar.gz" is a file extension, and files with that extension are called "gzipped tar files": these terms should not be translated
<p>${_("File uploads must be gzipped tar files (.tar.gz) containing, at a minimum, a {filename} file.").format(filename='<code>course.xml</code>')}</p> <p>${_("File uploads must be gzipped tar files (.tar.gz) containing, at a minimum, a {filename} file.").format(filename='<code>course.xml</code>')}</p>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment