upload: Add form to upload images
The upload form allows users to upload images to the Dark Chest of Wonders screenshot gallery. No authentication, etc. is performed, so this needs to be handled by the web server.master
parent
65f1a46d17
commit
ab5a41f686
|
@ -3,6 +3,7 @@ from . import (
|
|||
base,
|
||||
gallery,
|
||||
thumbnails,
|
||||
upload,
|
||||
)
|
||||
import functools
|
||||
import logging
|
||||
|
@ -40,6 +41,7 @@ class Application(milla.Application):
|
|||
|
||||
r.add_route('/', gallery.GalleryController())
|
||||
r.add_route('/thumbnails/{image}', thumbnails.ThumbnailController())
|
||||
r.add_route('/upload', upload.UploadController())
|
||||
|
||||
def make_request(self, environ):
|
||||
request = super(Application, self).make_request(environ)
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
</div>
|
||||
{% block body %}
|
||||
{% endblock body -%}
|
||||
{% block script -%}
|
||||
<script
|
||||
src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js">
|
||||
</script>
|
||||
{% endblock script -%}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
{% extends "base.html.j2" %}
|
||||
{% block head -%}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet"
|
||||
href="//cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.18.0/css/jquery.fileupload.min.css" />
|
||||
{% endblock head %}
|
||||
{% block body -%}
|
||||
<div class="row column">
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
<span id="select-file">
|
||||
<input type="file" id="fileupload" name="file" accept=".png,.jpg,.jpeg,.bmp" />
|
||||
</span>
|
||||
<div id="submit-button">
|
||||
<button type="submit" class="button">Submit</button>
|
||||
</div>
|
||||
<div id="progress" class="progress hide">
|
||||
<div class="progress-meter" style="width: 0;"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row column">
|
||||
<span id="results" class="form-error{{ ' is-visible' if error is defined }}">
|
||||
{%- if error is defined %}
|
||||
{{ error.message }}
|
||||
{% endif -%}
|
||||
</span>
|
||||
</div>
|
||||
{% endblock body -%}
|
||||
{% block script -%}
|
||||
{{ super() }}
|
||||
<script
|
||||
src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js">
|
||||
</script>
|
||||
<script
|
||||
src="//cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.18.0/js/jquery.iframe-transport.min.js">
|
||||
</script>
|
||||
<script
|
||||
src="//cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.18.0/js/jquery.fileupload.min.js">
|
||||
</script>
|
||||
<script>
|
||||
/* <![CDATA[ */
|
||||
$('#select-file').addClass('button fileinput-button')
|
||||
.append('<span>Select File…</span>');
|
||||
$('#submit-button').addClass('hide');
|
||||
$('#progress').removeClass('hide');
|
||||
$('#fileupload').fileupload({
|
||||
url: '',
|
||||
dataType: 'json',
|
||||
submit: function(e, data) {
|
||||
$('#progress .progress-meter').css('width', '0')
|
||||
$('#progress').removeClass('alert success');
|
||||
$('#results').removeClass('is-visible').text('');
|
||||
},
|
||||
done: function(e, data) {
|
||||
$('#progress').addClass('success');
|
||||
window.location = '..';
|
||||
},
|
||||
fail: function(e, data) {
|
||||
$('#progress').addClass('alert');
|
||||
var error;
|
||||
try {
|
||||
error = data.jqXHR.responseJSON.error.message;
|
||||
} catch (e) {
|
||||
error = data.errorThrown;
|
||||
}
|
||||
$('#results').addClass('is-visible').text(error);
|
||||
},
|
||||
progressall: function(e, data) {
|
||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||
$('#progress .progress-meter').css('width', progress + '%');
|
||||
}
|
||||
});
|
||||
/* ]]> */
|
||||
</script>
|
||||
{% endblock script -%}
|
|
@ -0,0 +1,46 @@
|
|||
from . import gallery
|
||||
import errno
|
||||
import milla.controllers
|
||||
import os
|
||||
|
||||
|
||||
class UploadController(milla.controllers.HTTPVerbController):
|
||||
|
||||
def GET(self, request):
|
||||
# XXX blueimp jQuery File Upload plugin does not work in XML parser
|
||||
request.want = 'html'
|
||||
response = request.ResponseClass()
|
||||
response.set_payload('upload.html.j2')
|
||||
return response
|
||||
|
||||
def POST(self, request):
|
||||
screenshot_dir = request.config['gallery.screenshot_dir']
|
||||
f = request.POST['file']
|
||||
path = os.path.join(screenshot_dir, f.filename)
|
||||
try:
|
||||
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
|
||||
except (IOError, OSError) as e:
|
||||
if e.errno == errno.EEXIST:
|
||||
response = request.ResponseClass()
|
||||
response.status_int = milla.HTTPConflict.code
|
||||
response.set_payload('upload.html.j2', {
|
||||
'error': {
|
||||
'message':
|
||||
'Image {} already exists'.format(f.filename),
|
||||
'code': response.status_int,
|
||||
}
|
||||
})
|
||||
return response
|
||||
else:
|
||||
raise milla.HTTPServerError(
|
||||
'{}'.format(e),
|
||||
)
|
||||
else:
|
||||
with os.fdopen(fd, 'wb') as q:
|
||||
for d in iter(lambda: f.file.read(4096), b''):
|
||||
q.write(d)
|
||||
|
||||
if request.want == 'json':
|
||||
raise milla.HTTPCreated
|
||||
else:
|
||||
raise milla.HTTPSeeOther(location='/')
|
Loading…
Reference in New Issue