Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 1
# -*- coding: utf-8 -*-
2
#
3
# jQuery File Upload Plugin GAE Python Example 2.2.0
4
# https://github.com/blueimp/jQuery-File-Upload
5
#
6
# Copyright 2011, Sebastian Tschan
7
# https://blueimp.net
8
#
9
# Licensed under the MIT license:
10
# http://www.opensource.org/licenses/MIT
11
#
12
 
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
18
import re
19
import urllib
20
import webapp2
21
 
22
WEBSITE = 'https://blueimp.github.io/jQuery-File-Upload/'
23
MIN_FILE_SIZE = 1  # bytes
24
MAX_FILE_SIZE = 5000000  # bytes
25
IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)')
26
ACCEPT_FILE_TYPES = IMAGE_TYPES
27
THUMBNAIL_MODIFICATOR = '=s80'  # max width / height
28
EXPIRATION_TIME = 300  # seconds
29
 
30
 
31
def cleanup(blob_keys):
32
    blobstore.delete(blob_keys)
33
 
34
 
35
class UploadHandler(webapp2.RequestHandler):
36
 
37
    def initialize(self, request, response):
38
        super(UploadHandler, self).initialize(request, response)
39
        self.response.headers['Access-Control-Allow-Origin'] = '*'
40
        self.response.headers[
41
            'Access-Control-Allow-Methods'
42
        ] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE'
43
        self.response.headers[
44
            'Access-Control-Allow-Headers'
45
        ] = 'Content-Type, Content-Range, Content-Disposition'
46
 
47
    def validate(self, file):
48
        if file['size'] < MIN_FILE_SIZE:
49
            file['error'] = 'File is too small'
50
        elif file['size'] > MAX_FILE_SIZE:
51
            file['error'] = 'File is too big'
52
        elif not ACCEPT_FILE_TYPES.match(file['type']):
53
            file['error'] = 'Filetype not allowed'
54
        else:
55
            return True
56
        return False
57
 
58
    def get_file_size(self, file):
59
        file.seek(0, 2)  # Seek to the end of the file
60
        size = file.tell()  # Get the position of EOF
61
        file.seek(0)  # Reset the file position to the beginning
62
        return size
63
 
64
    def write_blob(self, data, info):
65
        blob = files.blobstore.create(
66
            mime_type=info['type'],
67
            _blobinfo_uploaded_filename=info['name']
68
        )
69
        with files.open(blob, 'a') as f:
70
            f.write(data)
71
        files.finalize(blob)
72
        return files.blobstore.get_blob_key(blob)
73
 
74
    def handle_upload(self):
75
        results = []
76
        blob_keys = []
77
        for name, fieldStorage in self.request.POST.items():
78
            if type(fieldStorage) is unicode:
79
                continue
80
            result = {}
81
            result['name'] = re.sub(
82
                r'^.*\\',
83
                '',
84
                fieldStorage.filename
85
            )
86
            result['type'] = fieldStorage.type
87
            result['size'] = self.get_file_size(fieldStorage.file)
88
            if self.validate(result):
89
                blob_key = str(
90
                    self.write_blob(fieldStorage.value, result)
91
                )
92
                blob_keys.append(blob_key)
93
                result['deleteType'] = 'DELETE'
94
                result['deleteUrl'] = self.request.host_url +\
95
                    '/?key=' + urllib.quote(blob_key, '')
96
                if (IMAGE_TYPES.match(result['type'])):
97
                    try:
98
                        result['url'] = images.get_serving_url(
99
                            blob_key,
100
                            secure_url=self.request.host_url.startswith(
101
                                'https'
102
                            )
103
                        )
104
                        result['thumbnailUrl'] = result['url'] +\
105
                            THUMBNAIL_MODIFICATOR
106
                    except:  # Could not get an image serving url
107
                        pass
108
                if not 'url' in result:
109
                    result['url'] = self.request.host_url +\
110
                        '/' + blob_key + '/' + urllib.quote(
111
                            result['name'].encode('utf-8'), '')
112
            results.append(result)
113
        deferred.defer(
114
            cleanup,
115
            blob_keys,
116
            _countdown=EXPIRATION_TIME
117
        )
118
        return results
119
 
120
    def options(self):
121
        pass
122
 
123
    def head(self):
124
        pass
125
 
126
    def get(self):
127
        self.redirect(WEBSITE)
128
 
129
    def post(self):
130
        if (self.request.get('_method') == 'DELETE'):
131
            return self.delete()
132
        result = {'files': self.handle_upload()}
133
        s = json.dumps(result, separators=(',', ':'))
134
        redirect = self.request.get('redirect')
135
        if redirect:
136
            return self.redirect(str(
137
                redirect.replace('%s', urllib.quote(s, ''), 1)
138
            ))
139
        if 'application/json' in self.request.headers.get('Accept'):
140
            self.response.headers['Content-Type'] = 'application/json'
141
        self.response.write(s)
142
 
143
    def delete(self):
144
        key = self.request.get('key') or ''
145
        blobstore.delete(key)
146
        s = json.dumps({key: True}, separators=(',', ':'))
147
        if 'application/json' in self.request.headers.get('Accept'):
148
            self.response.headers['Content-Type'] = 'application/json'
149
        self.response.write(s)
150
 
151
 
152
class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler):
153
    def get(self, key, filename):
154
        if not blobstore.get(key):
155
            self.error(404)
156
        else:
157
            # Prevent browsers from MIME-sniffing the content-type:
158
            self.response.headers['X-Content-Type-Options'] = 'nosniff'
159
            # Cache for the expiration time:
160
            self.response.headers['Cache-Control'] = 'public,max-age=%d' % EXPIRATION_TIME
161
            # Send the file forcing a download dialog:
162
            self.send_blob(key, save_as=filename, content_type='application/octet-stream')
163
 
164
app = webapp2.WSGIApplication(
165
    [
166
        ('/', UploadHandler),
167
        ('/([^/]+)/([^/]+)', DownloadHandler)
168
    ],
169
    debug=True
170
)