Switched to dropzone
This commit is contained in:
parent
ef988708d8
commit
665694e305
5
.gitignore
vendored
5
.gitignore
vendored
@ -2,4 +2,7 @@ __pycache__
|
|||||||
*.pyc
|
*.pyc
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
credentials
|
credentials
|
||||||
polyphonic/settings.py
|
polyphonic/settings.py
|
||||||
|
env
|
||||||
|
text.*
|
||||||
|
static
|
||||||
33
Makefile
33
Makefile
@ -1,12 +1,27 @@
|
|||||||
DROPZONE=https://github.com/enyo/dropzone/archive/v5.7.0.zip
|
PYTHON=env/bin/python
|
||||||
|
DROPZONE=5.7.0
|
||||||
|
|
||||||
dev-setup:
|
dev-setup:
|
||||||
pip install -r requirements.txt
|
env/bin/pip install -r requirements.txt
|
||||||
pip install -r dev-requirements.txt
|
env/bin/pip install -r dev-requirements.txt
|
||||||
./manage.py migrate
|
${PYTHON} manage.py migrate
|
||||||
./manage.py createsuperuser --username admin --email admin@localhost
|
${PYTHON} manage.py createsuperuser --username admin --email admin@localhost
|
||||||
|
|
||||||
interface/static/dropzone/dropzone.js:
|
upgrade:
|
||||||
wget -O dropzone.zip ${DROPZONE}
|
${PYTHON} manage.py migrate
|
||||||
unzip -d interface/static dropzone.zip
|
${PYTHON} manage.py collectstatic
|
||||||
|
${MAKE} libraries
|
||||||
|
|
||||||
|
libraries: static/dropzone static/fonts/Quicksand_Book.otf
|
||||||
|
|
||||||
|
static/dropzone:
|
||||||
|
wget -O dropzone-${DROPZONE}.zip https://github.com/enyo/dropzone/archive/v${DROPZONE}.zip
|
||||||
|
unzip dropzone-${DROPZONE}.zip
|
||||||
|
mv dropzone-${DROPZONE}/dist static/dropzone
|
||||||
|
rm -rf dropzone-${DROPZONE} dropzone-${DROPZONE}.zip
|
||||||
|
|
||||||
|
static/fonts/Quicksand_Book.otf:
|
||||||
|
wget -O quicksand.zip https://dl.dafont.com/dl/?f=quicksand
|
||||||
|
mkdir -p static/fonts
|
||||||
|
unzip -d static/fonts quicksand.zip
|
||||||
|
rm quicksand.zip
|
||||||
18
interface/migrations/0016_auto_20200910_2025.py
Normal file
18
interface/migrations/0016_auto_20200910_2025.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 3.1.1 on 2020-09-10 10:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('interface', '0015_resource_media_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='resource',
|
||||||
|
name='media_type',
|
||||||
|
field=models.CharField(choices=[('audio', 'Audio'), ('video', 'Video'), ('general', 'General')], default='*', max_length=10),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -18,7 +18,7 @@ BUCKET = settings.AWS_BUCKET
|
|||||||
MEDIA_TYPES = [
|
MEDIA_TYPES = [
|
||||||
('audio', "Audio"),
|
('audio', "Audio"),
|
||||||
('video', "Video"),
|
('video', "Video"),
|
||||||
('*', "General"),
|
('general', "General"),
|
||||||
]
|
]
|
||||||
|
|
||||||
def generate_code(length=9):
|
def generate_code(length=9):
|
||||||
@ -63,7 +63,12 @@ class Resource(models.Model):
|
|||||||
media_type = models.CharField(max_length=10, choices=MEDIA_TYPES, default='*')
|
media_type = models.CharField(max_length=10, choices=MEDIA_TYPES, default='*')
|
||||||
|
|
||||||
def key_template(self):
|
def key_template(self):
|
||||||
return "{}_${{filename}}".format(slugify(self.name))
|
return "{}/${{filename}}".format(slugify(self.name))
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
if self.media_type == 'general':
|
||||||
|
return ".*"
|
||||||
|
return f"{self.media_type}/*"
|
||||||
|
|
||||||
def presigned_url(self):
|
def presigned_url(self):
|
||||||
if not self.key:
|
if not self.key:
|
||||||
|
|||||||
@ -5,11 +5,6 @@
|
|||||||
--light-blue: #c5eff7;
|
--light-blue: #c5eff7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'DreamOrphans';
|
|
||||||
src: url('../../fonts/dream orphans.ttf') format('truetype');
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Quicksand';
|
font-family: 'Quicksand';
|
||||||
src: url('../../fonts/Quicksand_Book.otf');
|
src: url('../../fonts/Quicksand_Book.otf');
|
||||||
@ -102,7 +97,7 @@ UL.nav-buttons > LI {
|
|||||||
|
|
||||||
/* FORMS */
|
/* FORMS */
|
||||||
|
|
||||||
FORM {
|
FORM.vertical {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
@ -221,4 +216,8 @@ TABLE.horizontal TH {
|
|||||||
.resource-player {
|
.resource-player {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dz-clickable {
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
@ -4,7 +4,7 @@
|
|||||||
<div class="narrow">
|
<div class="narrow">
|
||||||
<h3>{{ title }}</h3>
|
<h3>{{ title }}</h3>
|
||||||
<p>{{ instructions }}</p>
|
<p>{{ instructions }}</p>
|
||||||
<form method="POST">
|
<form class="vertical" method="POST">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form }}
|
{{ form }}
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
|||||||
@ -11,12 +11,12 @@
|
|||||||
{{ resource.name }}
|
{{ resource.name }}
|
||||||
{% if download %}
|
{% if download %}
|
||||||
<a href="{{ download }}">
|
<a href="{{ download }}">
|
||||||
<i class="fas fa-download"></i>
|
<i class="fas fa-download"></i> Download
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
<a href="{% url 'resource_upload' project=project.pk pk=resource.pk %}">
|
<a href="{% url 'resource_upload' project=project.pk pk=resource.pk %}">
|
||||||
<i class="fas fa-upload"></i>
|
<i class="fas fa-upload"></i> Upload
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</h3>
|
</h3>
|
||||||
|
|||||||
82
interface/templates/interface/s3_upload.html
Normal file
82
interface/templates/interface/s3_upload.html
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
|
<div class="narrow">
|
||||||
|
<h3 id="status">Select a file for upload</h3>
|
||||||
|
<form method="POST" action="{{ upload.url }}" enctype="multipart/form-data" id="item-upload" class="dropzone">
|
||||||
|
<div class="fallback">
|
||||||
|
{% for field, value in upload.fields.items %}
|
||||||
|
<input type="hidden" name="{{ field }}" value="{{ value }}" />
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<input name="file" type="file" accept="{{ media_type }}/*" id="fallback-file"/>
|
||||||
|
<input type="submit" value="Send" id="fallback-upload"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="form-actions text-right">
|
||||||
|
<a class=""
|
||||||
|
href="{{ cancel_url }}">Cancel</a>
|
||||||
|
|
||||||
|
<button type="submit" id="upload" disabled>Upload</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<link rel="stylesheet" href="{% static 'dropzone/dropzone.css' %}"/>
|
||||||
|
<script src="{% static 'dropzone/dropzone.js' %}"></script>
|
||||||
|
{{ ajax_upload|json_script:"dropzone-data" }}
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
const dzData = JSON.parse(document.getElementById('dropzone-data').textContent);
|
||||||
|
console.log(dzData);
|
||||||
|
|
||||||
|
let status = $('#status');
|
||||||
|
let uploadBtn = $('#upload');
|
||||||
|
|
||||||
|
$('#fallback-upload').on('click', function() {
|
||||||
|
status.html('Uploading - please wait...');
|
||||||
|
}).attr('disabled', true);
|
||||||
|
|
||||||
|
$('#fallback-file').on('change', function() {
|
||||||
|
status.html('Ready to upload');
|
||||||
|
$('#fallback-upload').attr('disabled', false);
|
||||||
|
});
|
||||||
|
|
||||||
|
Dropzone.options.itemUpload = {
|
||||||
|
params: dzData['fields'],
|
||||||
|
forceFallback: {{ request.GET.fallback|yesno:"true,false,false" }},
|
||||||
|
autoProcessQueue: false,
|
||||||
|
createImageThumbnails: false,
|
||||||
|
maxFiles: 1,
|
||||||
|
addRemoveLinks: true,
|
||||||
|
maxFilesize: 500,
|
||||||
|
dictDefaultMessage: "Select a file to upload (max 500Mb)",
|
||||||
|
dictFallbackMessage: "Your browser is old!, using alternative method",
|
||||||
|
init: function() {
|
||||||
|
let dz = this;
|
||||||
|
uploadBtn.on('click', function() {
|
||||||
|
dz.processQueue();
|
||||||
|
});
|
||||||
|
this.on('addedfile', function(f) {
|
||||||
|
status.html('Ready to upload...');
|
||||||
|
uploadBtn.attr('disabled', false);
|
||||||
|
});
|
||||||
|
this.on('sending', function(f) {
|
||||||
|
status.html('Uploading - please wait...');
|
||||||
|
});
|
||||||
|
this.on('success', function(f) {
|
||||||
|
status.html("Upload successfull");
|
||||||
|
//if (! confirm("Upload complete - redirect?")) return;
|
||||||
|
let s3_location = f.xhr.getResponseHeader("Location");
|
||||||
|
location.href = "{{ success_url }}?location=" + s3_location;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@ -9,7 +9,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<form action="" method="POST" enctype="multipart/form-data">
|
<form class="vertical" action="" method="POST" enctype="multipart/form-data">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form }}
|
{{ form }}
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
|||||||
@ -1,99 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
|
|
||||||
<div class="narrow">
|
|
||||||
<h3>Ready to upload file</h3>
|
|
||||||
<form method="POST" action="{{ upload.url }}" enctype="multipart/form-data" id="video-upload">
|
|
||||||
{% for field, value in upload.fields.items %}
|
|
||||||
<input type="hidden" name="{{ field }}" value="{{ value }}" />
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<input name="file" type="file" accept="video/*" />
|
|
||||||
|
|
||||||
<div class="progress">
|
|
||||||
<div class="progress-bar"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions text-right">
|
|
||||||
<a class=""
|
|
||||||
href="{{ cancel_url }}">Cancel</a>
|
|
||||||
|
|
||||||
<button type="submit" id="upload">Upload</button>
|
|
||||||
</div>
|
|
||||||
<div id="status">Select a file to upload</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/4.3.0/jquery.form.min.js" integrity="sha384-qlmct0AOBiA2VPZkMY3+2WqkHtIQ9lSdAsAn5RUJD/3vA5MKDgSGcdmIv4ycVxyn" crossorigin="anonymous"></script>
|
|
||||||
<script>
|
|
||||||
|
|
||||||
function uploadReady(e) {
|
|
||||||
$('#upload').attr('disabled', false);
|
|
||||||
$('#status').html('Ready to upload');
|
|
||||||
}
|
|
||||||
|
|
||||||
function startUpload(e) {
|
|
||||||
|
|
||||||
var bar = $('.progress-bar');
|
|
||||||
var percent = $('.percent');
|
|
||||||
var status = $('#status');
|
|
||||||
|
|
||||||
console.log("STARTING");
|
|
||||||
|
|
||||||
// disable file select and submit
|
|
||||||
e.target.disabled = true;
|
|
||||||
//$('input[name="file"]').attr('disabled', true);
|
|
||||||
|
|
||||||
// patch form to use our ajax policy
|
|
||||||
$('input[name="policy"]').val("{{ ajax_upload.fields.policy }}");
|
|
||||||
$('input[name="signature"]').val("{{ ajax_upload.fields.signature }}");
|
|
||||||
$('input[name="success_action_redirect"]').remove();
|
|
||||||
|
|
||||||
|
|
||||||
$('form').ajaxForm({
|
|
||||||
beforeSend: function() {
|
|
||||||
|
|
||||||
status.html("Starting upload");
|
|
||||||
var percentVal = '0%';
|
|
||||||
bar.width(percentVal)
|
|
||||||
percent.html(percentVal);
|
|
||||||
},
|
|
||||||
uploadProgress: function(event, position, total, percentComplete) {
|
|
||||||
var percentVal = percentComplete + '%';
|
|
||||||
bar.width(percentVal)
|
|
||||||
percent.html(percentVal);
|
|
||||||
},
|
|
||||||
success: function() {
|
|
||||||
console.log("success");
|
|
||||||
var percentVal = '100%';
|
|
||||||
bar.width(percentVal)
|
|
||||||
percent.html(percentVal);
|
|
||||||
},
|
|
||||||
complete: function(xhr) {
|
|
||||||
if (xhr.status == 204) {
|
|
||||||
status.html("Finished upload");
|
|
||||||
let s3_location = xhr.getResponseHeader("Location");
|
|
||||||
location.href = "{{ success_url }}?location=" + s3_location;
|
|
||||||
} else {
|
|
||||||
status.html("Something went wrong");
|
|
||||||
console.log(xhr.responseText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable ajax upload
|
|
||||||
$('input[name="file"]').on('change', uploadReady);
|
|
||||||
$('#upload').on('click', startUpload).attr('disabled', true);
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
@ -46,6 +46,10 @@ class ProjectMixin(EnsembleMixin):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
class S3UploadMixin(ProjectMixin):
|
class S3UploadMixin(ProjectMixin):
|
||||||
|
media_type = ''
|
||||||
|
|
||||||
|
def get_media_type(self):
|
||||||
|
return self.media_type
|
||||||
|
|
||||||
def get_cancel_url(self):
|
def get_cancel_url(self):
|
||||||
return self.cancel_url
|
return self.cancel_url
|
||||||
@ -64,6 +68,7 @@ class S3UploadMixin(ProjectMixin):
|
|||||||
context['ajax_upload'] = project.presigned_post(key_template)
|
context['ajax_upload'] = project.presigned_post(key_template)
|
||||||
context['success_url'] = success_url
|
context['success_url'] = success_url
|
||||||
context['cancel_url'] = self.get_cancel_url()
|
context['cancel_url'] = self.get_cancel_url()
|
||||||
|
context['media_type'] = self.media_type
|
||||||
return context
|
return context
|
||||||
|
|
||||||
class S3CompleteMixin(View):
|
class S3CompleteMixin(View):
|
||||||
@ -176,6 +181,7 @@ class SubmissionDetailView(ProjectMixin, S3CompleteMixin, DetailView):
|
|||||||
class SubmissionUploadView(S3UploadMixin, DetailView):
|
class SubmissionUploadView(S3UploadMixin, DetailView):
|
||||||
template_name = 'interface/s3_upload.html'
|
template_name = 'interface/s3_upload.html'
|
||||||
model = models.Submission
|
model = models.Submission
|
||||||
|
media_type = "video"
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return resolve_url('submission_detail', **self.kwargs)
|
return resolve_url('submission_detail', **self.kwargs)
|
||||||
@ -209,7 +215,10 @@ class ResourceCreateView(ProjectMixin, CreateView):
|
|||||||
|
|
||||||
class ResourceUploadView(S3UploadMixin, DetailView):
|
class ResourceUploadView(S3UploadMixin, DetailView):
|
||||||
model = models.Resource
|
model = models.Resource
|
||||||
template_name = 'interface/submission_upload.html'
|
template_name = 'interface/s3_upload.html'
|
||||||
|
|
||||||
|
def get_media_type(self):
|
||||||
|
return self.object.accept()
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return resolve_url('resource_complete', **self.kwargs)
|
return resolve_url('resource_complete', **self.kwargs)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user