1 # -*- coding: utf-8 -*-
3 # jQuery File Upload Plugin GAE Python Example 1.1.4
4 # https://github.com/blueimp/jQuery-File-Upload
6 # Copyright 2011, Sebastian Tschan
9 # Licensed under the MIT license:
10 # http://www.opensource.org/licenses/MIT
13 from __future__ import with_statement
14 from google.appengine.api import files, images
15 from google.appengine.ext import blobstore, deferred
16 from google.appengine.ext.webapp import blobstore_handlers
17 import json, re, urllib, webapp2
19 WEBSITE = 'http://blueimp.github.com/jQuery-File-Upload/'
20 MIN_FILE_SIZE = 1 # bytes
21 MAX_FILE_SIZE = 5000000 # bytes
22 IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
23 ACCEPT_FILE_TYPES = IMAGE_TYPES
24 THUMBNAIL_MODIFICATOR = '=s80' # max width / height
25 EXPIRATION_TIME = 300 # seconds
27 def cleanup(blob_keys):
28 blobstore.delete(blob_keys)
30 class UploadHandler(webapp2.RequestHandler):
32 def initialize(self, request, response):
33 super(UploadHandler, self).initialize(request, response)
34 self.response.headers['Access-Control-Allow-Origin'] = '*'
35 self.response.headers[
36 'Access-Control-Allow-Methods'
37 ] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE'
39 def validate(self, file):
40 if file['size'] < MIN_FILE_SIZE:
41 file['error'] = 'minFileSize'
42 elif file['size'] > MAX_FILE_SIZE:
43 file['error'] = 'maxFileSize'
44 elif not ACCEPT_FILE_TYPES.match(file['type']):
45 file['error'] = 'acceptFileTypes'
50 def get_file_size(self, file):
51 file.seek(0, 2) # Seek to the end of the file
52 size = file.tell() # Get the position of EOF
53 file.seek(0) # Reset the file position to the beginning
56 def write_blob(self, data, info):
57 blob = files.blobstore.create(
58 mime_type=info['type'],
59 _blobinfo_uploaded_filename=info['name']
61 with files.open(blob, 'a') as f:
64 return files.blobstore.get_blob_key(blob)
66 def handle_upload(self):
69 for name, fieldStorage in self.request.POST.items():
70 if type(fieldStorage) is unicode:
73 result['name'] = re.sub(r'^.*\\', '',
74 fieldStorage.filename)
75 result['type'] = fieldStorage.type
76 result['size'] = self.get_file_size(fieldStorage.file)
77 if self.validate(result):
79 self.write_blob(fieldStorage.value, result)
81 blob_keys.append(blob_key)
82 result['delete_type'] = 'DELETE'
83 result['delete_url'] = self.request.host_url +\
84 '/?key=' + urllib.quote(blob_key, '')
85 if (IMAGE_TYPES.match(result['type'])):
87 result['url'] = images.get_serving_url(
89 secure_url=self.request.host_url\
92 result['thumbnail_url'] = result['url'] +\
94 except: # Could not get an image serving url
96 if not 'url' in result:
97 result['url'] = self.request.host_url +\
98 '/' + blob_key + '/' + urllib.quote(
99 result['name'].encode('utf-8'), '')
100 results.append(result)
104 _countdown=EXPIRATION_TIME
115 self.redirect(WEBSITE)
118 if (self.request.get('_method') == 'DELETE'):
120 s = json.dumps(self.handle_upload(), separators=(',',':'))
121 redirect = self.request.get('redirect')
123 return self.redirect(str(
124 redirect.replace('%s', urllib.quote(s, ''), 1)
126 if 'application/json' in self.request.headers.get('Accept'):
127 self.response.headers['Content-Type'] = 'application/json'
128 self.response.write(s)
131 blobstore.delete(self.request.get('key') or '')
133 class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):
134 def get(self, key, filename):
135 if not blobstore.get(key):
138 # Cache for the expiration time:
139 self.response.headers['Cache-Control'] =\
140 'public,max-age=%d' % EXPIRATION_TIME
141 self.send_blob(key, save_as=filename)
143 app = webapp2.WSGIApplication(
145 ('/', UploadHandler),
146 ('/([^/]+)/([^/]+)', DownloadHandler)