mirror of
https://github.com/YunoHost-Apps/hubzilla_ynh.git
synced 2024-09-03 19:26:21 +02:00
171 lines
5.7 KiB
Python
171 lines
5.7 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
#
|
||
|
# jQuery File Upload Plugin GAE Python Example 2.1.1
|
||
|
# https://github.com/blueimp/jQuery-File-Upload
|
||
|
#
|
||
|
# Copyright 2011, Sebastian Tschan
|
||
|
# https://blueimp.net
|
||
|
#
|
||
|
# Licensed under the MIT license:
|
||
|
# http://www.opensource.org/licenses/MIT
|
||
|
#
|
||
|
|
||
|
from __future__ import with_statement
|
||
|
from google.appengine.api import files, images
|
||
|
from google.appengine.ext import blobstore, deferred
|
||
|
from google.appengine.ext.webapp import blobstore_handlers
|
||
|
import json
|
||
|
import re
|
||
|
import urllib
|
||
|
import webapp2
|
||
|
|
||
|
WEBSITE = 'http://blueimp.github.io/jQuery-File-Upload/'
|
||
|
MIN_FILE_SIZE = 1 # bytes
|
||
|
MAX_FILE_SIZE = 5000000 # bytes
|
||
|
IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
|
||
|
ACCEPT_FILE_TYPES = IMAGE_TYPES
|
||
|
THUMBNAIL_MODIFICATOR = '=s80' # max width / height
|
||
|
EXPIRATION_TIME = 300 # seconds
|
||
|
|
||
|
|
||
|
def cleanup(blob_keys):
|
||
|
blobstore.delete(blob_keys)
|
||
|
|
||
|
|
||
|
class UploadHandler(webapp2.RequestHandler):
|
||
|
|
||
|
def initialize(self, request, response):
|
||
|
super(UploadHandler, self).initialize(request, response)
|
||
|
self.response.headers['Access-Control-Allow-Origin'] = '*'
|
||
|
self.response.headers[
|
||
|
'Access-Control-Allow-Methods'
|
||
|
] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE'
|
||
|
self.response.headers[
|
||
|
'Access-Control-Allow-Headers'
|
||
|
] = 'Content-Type, Content-Range, Content-Disposition'
|
||
|
|
||
|
def validate(self, file):
|
||
|
if file['size'] < MIN_FILE_SIZE:
|
||
|
file['error'] = 'File is too small'
|
||
|
elif file['size'] > MAX_FILE_SIZE:
|
||
|
file['error'] = 'File is too big'
|
||
|
elif not ACCEPT_FILE_TYPES.match(file['type']):
|
||
|
file['error'] = 'Filetype not allowed'
|
||
|
else:
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
def get_file_size(self, file):
|
||
|
file.seek(0, 2) # Seek to the end of the file
|
||
|
size = file.tell() # Get the position of EOF
|
||
|
file.seek(0) # Reset the file position to the beginning
|
||
|
return size
|
||
|
|
||
|
def write_blob(self, data, info):
|
||
|
blob = files.blobstore.create(
|
||
|
mime_type=info['type'],
|
||
|
_blobinfo_uploaded_filename=info['name']
|
||
|
)
|
||
|
with files.open(blob, 'a') as f:
|
||
|
f.write(data)
|
||
|
files.finalize(blob)
|
||
|
return files.blobstore.get_blob_key(blob)
|
||
|
|
||
|
def handle_upload(self):
|
||
|
results = []
|
||
|
blob_keys = []
|
||
|
for name, fieldStorage in self.request.POST.items():
|
||
|
if type(fieldStorage) is unicode:
|
||
|
continue
|
||
|
result = {}
|
||
|
result['name'] = re.sub(
|
||
|
r'^.*\\',
|
||
|
'',
|
||
|
fieldStorage.filename
|
||
|
)
|
||
|
result['type'] = fieldStorage.type
|
||
|
result['size'] = self.get_file_size(fieldStorage.file)
|
||
|
if self.validate(result):
|
||
|
blob_key = str(
|
||
|
self.write_blob(fieldStorage.value, result)
|
||
|
)
|
||
|
blob_keys.append(blob_key)
|
||
|
result['deleteType'] = 'DELETE'
|
||
|
result['deleteUrl'] = self.request.host_url +\
|
||
|
'/?key=' + urllib.quote(blob_key, '')
|
||
|
if (IMAGE_TYPES.match(result['type'])):
|
||
|
try:
|
||
|
result['url'] = images.get_serving_url(
|
||
|
blob_key,
|
||
|
secure_url=self.request.host_url.startswith(
|
||
|
'https'
|
||
|
)
|
||
|
)
|
||
|
result['thumbnailUrl'] = result['url'] +\
|
||
|
THUMBNAIL_MODIFICATOR
|
||
|
except: # Could not get an image serving url
|
||
|
pass
|
||
|
if not 'url' in result:
|
||
|
result['url'] = self.request.host_url +\
|
||
|
'/' + blob_key + '/' + urllib.quote(
|
||
|
result['name'].encode('utf-8'), '')
|
||
|
results.append(result)
|
||
|
deferred.defer(
|
||
|
cleanup,
|
||
|
blob_keys,
|
||
|
_countdown=EXPIRATION_TIME
|
||
|
)
|
||
|
return results
|
||
|
|
||
|
def options(self):
|
||
|
pass
|
||
|
|
||
|
def head(self):
|
||
|
pass
|
||
|
|
||
|
def get(self):
|
||
|
self.redirect(WEBSITE)
|
||
|
|
||
|
def post(self):
|
||
|
if (self.request.get('_method') == 'DELETE'):
|
||
|
return self.delete()
|
||
|
result = {'files': self.handle_upload()}
|
||
|
s = json.dumps(result, separators=(',', ':'))
|
||
|
redirect = self.request.get('redirect')
|
||
|
if redirect:
|
||
|
return self.redirect(str(
|
||
|
redirect.replace('%s', urllib.quote(s, ''), 1)
|
||
|
))
|
||
|
if 'application/json' in self.request.headers.get('Accept'):
|
||
|
self.response.headers['Content-Type'] = 'application/json'
|
||
|
self.response.write(s)
|
||
|
|
||
|
def delete(self):
|
||
|
key = self.request.get('key') or ''
|
||
|
blobstore.delete(key)
|
||
|
s = json.dumps({key: True}, separators=(',', ':'))
|
||
|
if 'application/json' in self.request.headers.get('Accept'):
|
||
|
self.response.headers['Content-Type'] = 'application/json'
|
||
|
self.response.write(s)
|
||
|
|
||
|
|
||
|
class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):
|
||
|
def get(self, key, filename):
|
||
|
if not blobstore.get(key):
|
||
|
self.error(404)
|
||
|
else:
|
||
|
# Prevent browsers from MIME-sniffing the content-type:
|
||
|
self.response.headers['X-Content-Type-Options'] = 'nosniff'
|
||
|
# Cache for the expiration time:
|
||
|
self.response.headers['Cache-Control'] = 'public,max-age=%d' % EXPIRATION_TIME
|
||
|
# Send the file forcing a download dialog:
|
||
|
self.send_blob(key, save_as=filename, content_type='application/octet-stream')
|
||
|
|
||
|
app = webapp2.WSGIApplication(
|
||
|
[
|
||
|
('/', UploadHandler),
|
||
|
('/([^/]+)/([^/]+)', DownloadHandler)
|
||
|
],
|
||
|
debug=True
|
||
|
)
|