Merge pull request #823 from edx/jkarni/feature/multiple-assets-upload
Add support for multiple file uploads
This commit is contained in:
@@ -10,6 +10,16 @@ Feature: Upload Files
|
|||||||
Then I should see the file "test" was uploaded
|
Then I should see the file "test" was uploaded
|
||||||
And The url for the file "test" is valid
|
And The url for the file "test" is valid
|
||||||
|
|
||||||
|
@skip_safari
|
||||||
|
Scenario: Users can upload multiple files
|
||||||
|
Given I have opened a new course in studio
|
||||||
|
And I go to the files and uploads page
|
||||||
|
When I upload the files "test","test2"
|
||||||
|
Then I should see the file "test" was uploaded
|
||||||
|
And I should see the file "test2" was uploaded
|
||||||
|
And The url for the file "test2" is valid
|
||||||
|
And The url for the file "test" is valid
|
||||||
|
|
||||||
# Uploading isn't working on safari with sauce labs
|
# Uploading isn't working on safari with sauce labs
|
||||||
@skip_safari
|
@skip_safari
|
||||||
Scenario: Users can update files
|
Scenario: Users can update files
|
||||||
|
|||||||
@@ -26,7 +26,24 @@ def upload_file(_step, file_name):
|
|||||||
#uploading the file itself
|
#uploading the file itself
|
||||||
path = os.path.join(TEST_ROOT, 'uploads/', file_name)
|
path = os.path.join(TEST_ROOT, 'uploads/', file_name)
|
||||||
world.browser.execute_script("$('input.file-input').css('display', 'block')")
|
world.browser.execute_script("$('input.file-input').css('display', 'block')")
|
||||||
world.browser.attach_file('file', os.path.abspath(path))
|
world.browser.attach_file('files[]', os.path.abspath(path))
|
||||||
|
close_css = 'a.close-button'
|
||||||
|
world.css_click(close_css)
|
||||||
|
|
||||||
|
|
||||||
|
@step(u'I upload the files (".*")$')
|
||||||
|
def upload_file(_step, files_string):
|
||||||
|
# Turn files_string to a list of file names
|
||||||
|
files = files_string.split(",")
|
||||||
|
files = map(lambda x: string.strip(x, ' "\''), files)
|
||||||
|
|
||||||
|
upload_css = 'a.upload-button'
|
||||||
|
world.css_click(upload_css)
|
||||||
|
#uploading the files
|
||||||
|
for f in files:
|
||||||
|
path = os.path.join(TEST_ROOT, 'uploads/', f)
|
||||||
|
world.browser.execute_script("$('input.file-input').css('display', 'block')")
|
||||||
|
world.browser.attach_file('files[]', os.path.abspath(path))
|
||||||
close_css = 'a.close-button'
|
close_css = 'a.close-button'
|
||||||
world.css_click(close_css)
|
world.css_click(close_css)
|
||||||
|
|
||||||
|
|||||||
@@ -149,14 +149,14 @@ def upload_asset(request, org, course, coursename):
|
|||||||
logging.error('Could not find course' + location)
|
logging.error('Could not find course' + location)
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
if 'file' not in request.FILES:
|
if 'files[]' not in request.FILES:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
# compute a 'filename' which is similar to the location formatting, we're
|
# compute a 'filename' which is similar to the location formatting, we're
|
||||||
# using the 'filename' nomenclature since we're using a FileSystem paradigm
|
# using the 'filename' nomenclature since we're using a FileSystem paradigm
|
||||||
# here. We're just imposing the Location string formatting expectations to
|
# here. We're just imposing the Location string formatting expectations to
|
||||||
# keep things a bit more consistent
|
# keep things a bit more consistent
|
||||||
upload_file = request.FILES['file']
|
upload_file = request.FILES['files[]']
|
||||||
filename = upload_file.name
|
filename = upload_file.name
|
||||||
mime_type = upload_file.content_type
|
mime_type = upload_file.content_type
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,29 @@ function removeAsset(e){
|
|||||||
|
|
||||||
function showUploadModal(e) {
|
function showUploadModal(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
resetUploadModal();
|
||||||
$modal = $('.upload-modal').show();
|
$modal = $('.upload-modal').show();
|
||||||
|
$('.upload-modal .file-chooser').fileupload({
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'POST',
|
||||||
|
maxChunkSize: 100 * 1000 * 1000, // 100 MB
|
||||||
|
autoUpload: true,
|
||||||
|
progressall: function(e, data) {
|
||||||
|
var percentComplete = parseInt((100 * data.loaded) / data.total, 10);
|
||||||
|
showUploadFeedback(e, percentComplete);
|
||||||
|
},
|
||||||
|
maxFileSize: 100 * 1000 * 1000, // 100 MB
|
||||||
|
maxNumberofFiles: 100,
|
||||||
|
add: function(e, data) {
|
||||||
|
data.process().done(function () {
|
||||||
|
data.submit();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
done: function(e, data) {
|
||||||
|
displayFinishedUpload(data.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
$('.file-input').bind('change', startUpload);
|
$('.file-input').bind('change', startUpload);
|
||||||
$modalCover.show();
|
$modalCover.show();
|
||||||
}
|
}
|
||||||
@@ -69,11 +91,6 @@ function startUpload(e) {
|
|||||||
|
|
||||||
$('.upload-modal h1').html(gettext('Uploading…'));
|
$('.upload-modal h1').html(gettext('Uploading…'));
|
||||||
$('.upload-modal .file-name').html(files[0].name);
|
$('.upload-modal .file-name').html(files[0].name);
|
||||||
$('.upload-modal .file-chooser').ajaxSubmit({
|
|
||||||
beforeSend: resetUploadBar,
|
|
||||||
uploadProgress: showUploadFeedback,
|
|
||||||
complete: displayFinishedUpload
|
|
||||||
});
|
|
||||||
$('.upload-modal .choose-file-button').hide();
|
$('.upload-modal .choose-file-button').hide();
|
||||||
$('.upload-modal .progress-bar').removeClass('loaded').show();
|
$('.upload-modal .progress-bar').removeClass('loaded').show();
|
||||||
}
|
}
|
||||||
@@ -84,18 +101,28 @@ function resetUploadBar() {
|
|||||||
$('.upload-modal .progress-fill').html(percentVal);
|
$('.upload-modal .progress-fill').html(percentVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showUploadFeedback(event, position, total, percentComplete) {
|
function resetUploadModal() {
|
||||||
|
// Reset modal so it no longer displays information about previously
|
||||||
|
// completed uploads.
|
||||||
|
resetUploadBar();
|
||||||
|
$('.upload-modal .file-name').html('');
|
||||||
|
$('.upload-modal h1').html(gettext('Upload New File'));
|
||||||
|
$('.upload-modal .choose-file-button').html(gettext('Choose File'));
|
||||||
|
$('.upload-modal .embeddable-xml-input').val('');
|
||||||
|
$('.upload-modal .embeddable').hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showUploadFeedback(event, percentComplete) {
|
||||||
var percentVal = percentComplete + '%';
|
var percentVal = percentComplete + '%';
|
||||||
$('.upload-modal .progress-fill').width(percentVal);
|
$('.upload-modal .progress-fill').width(percentVal);
|
||||||
$('.upload-modal .progress-fill').html(percentVal);
|
$('.upload-modal .progress-fill').html(percentVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayFinishedUpload(xhr) {
|
function displayFinishedUpload(resp) {
|
||||||
if (xhr.status == 200) {
|
if (resp.status == 200) {
|
||||||
markAsLoaded();
|
markAsLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp = JSON.parse(xhr.responseText);
|
|
||||||
$('.upload-modal .embeddable-xml-input').val(resp.portable_url);
|
$('.upload-modal .embeddable-xml-input').val(resp.portable_url);
|
||||||
$('.upload-modal .embeddable').show();
|
$('.upload-modal .embeddable').show();
|
||||||
$('.upload-modal .file-name').hide();
|
$('.upload-modal .file-name').hide();
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
<%block name="jsextra">
|
<%block name="jsextra">
|
||||||
<script src="${static.url('js/vendor/mustache.js')}"></script>
|
<script src="${static.url('js/vendor/mustache.js')}"></script>
|
||||||
|
<script src="${static.url('js/vendor/jQuery-File-Upload/js/jquery.iframe-transport.js')}"> </script>
|
||||||
|
<script src="${static.url('js/vendor/jQuery-File-Upload/js/jquery.fileupload.js')}"> </script>
|
||||||
</%block>
|
</%block>
|
||||||
|
|
||||||
<%block name="content">
|
<%block name="content">
|
||||||
@@ -40,12 +42,12 @@
|
|||||||
<div class="wrapper-mast wrapper">
|
<div class="wrapper-mast wrapper">
|
||||||
<header class="mast has-actions has-subtitle">
|
<header class="mast has-actions has-subtitle">
|
||||||
<h1 class="page-header">
|
<h1 class="page-header">
|
||||||
<small class="subtitle">Content</small>
|
<small class="subtitle">${_("Content")}</small>
|
||||||
<span class="sr">> </span>Files & Uploads
|
<span class="sr">> </span>${_("Files & Uploads")}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<nav class="nav-actions">
|
<nav class="nav-actions">
|
||||||
<h3 class="sr">Page Actions</h3>
|
<h3 class="sr">${_("Page Actions")}</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a href="#" class="button upload-button new-button"><i class="icon-plus"></i> ${_("Upload New File")}</a>
|
<a href="#" class="button upload-button new-button"><i class="icon-plus"></i> ${_("Upload New File")}</a>
|
||||||
@@ -114,26 +116,26 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="upload-modal modal">
|
<div class="upload-modal modal">
|
||||||
<a href="#" class="close-button"><span class="close-icon"></span></a>
|
<a href="#" class="close-button"><span class="close-icon"></span></a>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<h1>Upload New File</h1>
|
<h1>${_("Upload New File")}</h1>
|
||||||
<p class="file-name"></a>
|
<p class="file-name"></a>
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
<div class="progress-fill"></div>
|
<div class="progress-fill"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="embeddable">
|
<div class="embeddable">
|
||||||
<label>URL:</label>
|
<label>URL:</label>
|
||||||
<input type="text" class="embeddable-xml-input" value='' readonly>
|
<input type="text" class="embeddable-xml-input" value='' readonly>
|
||||||
</div>
|
</div>
|
||||||
<form class="file-chooser" action="${upload_asset_callback_url}"
|
<form class="file-chooser" action="${upload_asset_callback_url}"
|
||||||
method="post" enctype="multipart/form-data">
|
method="post" enctype="multipart/form-data">
|
||||||
<a href="#" class="choose-file-button">Choose File</a>
|
<a href="#" class="choose-file-button">${_("Choose File")}</a>
|
||||||
<input type="file" class="file-input" name="file">
|
<input type="file" class="file-input" name="files[]" multiple>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-cover"></div>
|
<div class="modal-cover"></div>
|
||||||
|
|
||||||
|
|
||||||
</%block>
|
</%block>
|
||||||
|
|||||||
Reference in New Issue
Block a user