Route ajax request to appropriate view, and show feedback only then
Hook up view Fix getStatus function
This commit is contained in:
@@ -18,8 +18,8 @@ from django_future.csrf import ensure_csrf_cookie
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.servers.basehttp import FileWrapper
|
||||
from django.core.files.temp import NamedTemporaryFile
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.core.exceptions import SuspiciousOperation
|
||||
from django.views.decorators.http import require_http_methods, require_GET
|
||||
|
||||
from mitxmako.shortcuts import render_to_response
|
||||
from auth.authz import create_all_course_groups
|
||||
@@ -36,7 +36,7 @@ from util.json_request import JsonResponse
|
||||
from extract_tar import safetar_extractall
|
||||
|
||||
|
||||
__all__ = ['import_course', 'generate_export_course', 'export_course']
|
||||
__all__ = ['import_course', 'import_status', 'generate_export_course', 'export_course']
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -145,15 +145,15 @@ def import_course(request, org, course, name):
|
||||
|
||||
else: # This was the last chunk.
|
||||
|
||||
# 'Lock' with status info.
|
||||
status_file = data_root / (course + filename + ".lock")
|
||||
# Use sessions to keep info about import progress
|
||||
session_status = request.session.setdefault("import_status", {})
|
||||
key = org + course + filename
|
||||
session_status[key] = 1
|
||||
request.session.modified = True
|
||||
|
||||
# Do everything from now on in a with-context, to be sure we've
|
||||
# properly cleaned up.
|
||||
with wfile(status_file, course_dir):
|
||||
|
||||
with open(status_file, 'w+') as sf:
|
||||
sf.write("Extracting")
|
||||
# Do everything from now on in a try-finally block to make sure
|
||||
# everything is properly cleaned up.
|
||||
try:
|
||||
|
||||
tar_file = tarfile.open(temp_filepath)
|
||||
try:
|
||||
@@ -167,8 +167,8 @@ def import_course(request, org, course, name):
|
||||
status=400
|
||||
)
|
||||
|
||||
with open(status_file, 'w+') as sf:
|
||||
sf.write("Verifying")
|
||||
session_status[key] = 2
|
||||
request.session.modified = True
|
||||
|
||||
# find the 'course.xml' file
|
||||
dirpath = None
|
||||
@@ -221,12 +221,15 @@ def import_course(request, org, course, name):
|
||||
|
||||
logging.debug('new course at {0}'.format(course_items[0].location))
|
||||
|
||||
with open(status_file, 'w') as sf:
|
||||
sf.write("Updating course")
|
||||
session_status[key] = 3
|
||||
request.session.modified = True
|
||||
|
||||
create_all_course_groups(request.user, course_items[0].location)
|
||||
logging.debug('created all course groups at {0}'.format(course_items[0].location))
|
||||
|
||||
finally:
|
||||
shutil.rmtree(course_dir)
|
||||
|
||||
return JsonResponse({'Status': 'OK'})
|
||||
else:
|
||||
course_module = modulestore().get_item(location)
|
||||
@@ -240,33 +243,27 @@ def import_course(request, org, course, name):
|
||||
})
|
||||
})
|
||||
|
||||
@require_GET
|
||||
@ensure_csrf_cookie
|
||||
@login_required
|
||||
def get_import_status(request, course, filename):
|
||||
def import_status(request, org, course, name):
|
||||
"""
|
||||
Returns an integer corresponding to the status of a file import. These are:
|
||||
|
||||
0 : No status file found (import done or upload still in progress)
|
||||
0 : No status info found (import done or upload still in progress)
|
||||
1 : Extracting file
|
||||
2 : Validating.
|
||||
3 : Importing to mongo
|
||||
|
||||
4 : Error reading file (e.g., converting contents to int)
|
||||
|
||||
"""
|
||||
data_root = path(settings.GITHUB_REPO_ROOT)
|
||||
status_file = data_root / (course + filename + ".lock")
|
||||
if not os.path.isfile(status_file):
|
||||
return JsonResponse({"ImportStatus": 0 })
|
||||
|
||||
with open(status_file, "r") as f:
|
||||
try:
|
||||
status = int(f.read())
|
||||
except ValueError:
|
||||
status = 4
|
||||
return JsonResponse({"ImportStatus": status})
|
||||
|
||||
try:
|
||||
session_status = request.session["import_status"]
|
||||
status = session_status[org + course + name]
|
||||
except KeyError:
|
||||
status = 0
|
||||
|
||||
return JsonResponse({"ImportStatus": status })
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
|
||||
5
cms/static/sass/views/_import.scss
vendored
5
cms/static/sass/views/_import.scss
vendored
@@ -121,6 +121,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
div.status-info-block {
|
||||
display: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.not-started {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
@@ -35,24 +35,18 @@
|
||||
<input type="file" name="course-data" class="file-input" >
|
||||
<input type="submit" value="${_('Replace my course with the one above')}" class="submit-button" >
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}">
|
||||
<div id="status-infos" class="status-infos">
|
||||
<p class="status-info in-progress">
|
||||
<div id="status-info-block" class="status-info-block">
|
||||
<p class="status-info not-started">
|
||||
<i class="icon-check-empty"></i>
|
||||
Unpacking
|
||||
<span class="loading-dots">.</span>
|
||||
<span class="loading-dots">.</span>
|
||||
<span class="loading-dots">.</span>
|
||||
</p>
|
||||
<p class="status-info not-started">
|
||||
<i class="icon-check-empty"></i>
|
||||
Verifying
|
||||
<span class="loading-dots">.</span>
|
||||
<span class="loading-dots">.</span>
|
||||
<span class="loading-dots">.</span>
|
||||
</p>
|
||||
<p class="status-info not-started">
|
||||
<i class="icon-check-empty"></i>
|
||||
Importing
|
||||
<span class="loading-dots">.</span>
|
||||
<span class="loading-dots">.</span>
|
||||
<span class="loading-dots">.</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
@@ -69,6 +63,7 @@
|
||||
<script>
|
||||
require(["jquery", "jquery.fileupload"], function($) {
|
||||
|
||||
var file;
|
||||
var bar = $('.progress-bar');
|
||||
var fill = $('.progress-fill');
|
||||
var percent = $('.percent');
|
||||
@@ -78,6 +73,8 @@ var submitBtn = $('.submit-button');
|
||||
|
||||
var allStats = $('#status-infos');
|
||||
|
||||
var feedbackUrl = "${reverse('import_status', kwargs=dict(org=context_course.location.org, course=context_course.location.course, name='fillerName'))}"
|
||||
|
||||
|
||||
$('#fileupload').fileupload({
|
||||
|
||||
@@ -90,7 +87,7 @@ $('#fileupload').fileupload({
|
||||
|
||||
add: function(e, data) {
|
||||
submitBtn.unbind('click');
|
||||
var file = data.files[0];
|
||||
file = data.files[0];
|
||||
if (file.name.match(/tar\.gz$/)) {
|
||||
submitBtn.click(function(e){
|
||||
e.preventDefault();
|
||||
@@ -110,10 +107,25 @@ $('#fileupload').fileupload({
|
||||
},
|
||||
|
||||
progressall: function(e, data){
|
||||
var percentVal = parseInt(data.loaded / data.total * 100, 10) + "%";
|
||||
bar.show();
|
||||
fill.width(percentVal);
|
||||
percent.html(percentVal);
|
||||
var doneAt;
|
||||
var percentInt = data.loaded / data.total * 100
|
||||
var percentVal = parseInt(percentInt, 10) + "%";
|
||||
// Firefox makes ProgressEvent.loaded equal ProgressEvent.total only
|
||||
// after receiving a response from the server (see Mozilla bug 637002),
|
||||
// so for Firefox we jump the gun a little.
|
||||
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1) {
|
||||
doneAt = 95;
|
||||
} else {
|
||||
doneAt = 99;
|
||||
}
|
||||
if (percentInt >= doneAt) {
|
||||
bar.hide();
|
||||
startServerFeedback(feedbackUrl.replace("fillerName", file.name));
|
||||
} else {
|
||||
bar.show();
|
||||
fill.width(percentVal);
|
||||
percent.html(percentVal);
|
||||
}
|
||||
},
|
||||
done: function(e, data){
|
||||
bar.hide();
|
||||
|
||||
@@ -29,6 +29,8 @@ urlpatterns = ('', # nopep8
|
||||
'contentstore.views.course_index', name='course_index'),
|
||||
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/import/(?P<name>[^/]+)$',
|
||||
'contentstore.views.import_course', name='import_course'),
|
||||
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/import_status/(?P<name>[^/]+)$',
|
||||
'contentstore.views.import_status', name='import_status'),
|
||||
|
||||
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/export/(?P<name>[^/]+)$',
|
||||
'contentstore.views.export_course', name='export_course'),
|
||||
|
||||
Reference in New Issue
Block a user