4
4
# License, v. 2.0. If a copy of the MPL was not distributed with this
5
5
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
6
7
- '''Flask Blueprint for image uploads.'''
7
+ '''Flask Blueprint for file uploads.'''
8
8
9
9
import base64
10
10
import datetime
22
22
from werkzeug .exceptions import RequestEntityTooLarge
23
23
24
24
from webcompat import app
25
+ from webcompat .helpers import get_data_from_request
25
26
26
27
uploads = Blueprint ('uploads' , __name__ , url_prefix = '/upload' ,
27
28
template_folder = '../templates' )
28
29
JSON_MIME = 'application/json'
29
30
30
31
31
- class Upload (object ):
32
+ class BaseUpload (object ):
33
+ def __init__ (self ):
34
+ today = datetime .date .today ()
35
+ self .year = str (today .year )
36
+ self .month = str (today .month )
37
+ self .file_id = str (uuid .uuid4 ())
38
+
39
+ def get_file_path (self , year , month , file_id , ext , thumb = False ):
40
+ thumb_string = ''
41
+ if thumb :
42
+ thumb_string = '-thumb'
43
+ file_name = file_id + thumb_string + '.' + ext
44
+ return os .path .join (year , month , file_name )
45
+
46
+
47
+ class ImageUpload (BaseUpload ):
32
48
33
49
'''Class that abstracts over saving image and screenshot uploads.
34
50
@@ -39,17 +55,15 @@ class Upload(object):
39
55
ALLOWED_FORMATS = ('jpg' , 'jpeg' , 'jpe' , 'png' , 'gif' , 'bmp' )
40
56
41
57
def __init__ (self , imagedata ):
58
+ super ().__init__ ()
42
59
self .image_object = self .to_image_object (imagedata )
43
- # computing the parameters to be used
44
- today = datetime .date .today ()
45
- self .year = str (today .year )
46
- self .month = str (today .month )
47
- self .image_id = str (uuid .uuid4 ())
48
60
self .file_ext = self .get_file_ext ()
49
- self .image_path = self .img_path (self .month , self .year , self .image_id ,
50
- thumb = False )
51
- self .thumb_path = self .img_path (self .month , self .year , self .image_id ,
52
- thumb = True )
61
+ self .image_path = self .get_file_path (self .year , self .month ,
62
+ self .file_id , self .file_ext ,
63
+ thumb = False )
64
+ self .thumb_path = self .get_file_path (self .year , self .month ,
65
+ self .file_id , self .file_ext ,
66
+ thumb = True )
53
67
54
68
def to_image_object (self , imagedata ):
55
69
'''Method to return a Pillow Image object from the raw imagedata.'''
@@ -70,14 +84,6 @@ def to_image_object(self, imagedata):
70
84
# Not a valid format
71
85
abort (415 )
72
86
73
- def img_path (self , month , year , image_id , thumb = False ):
74
- '''Return the right image path.'''
75
- thumb_string = ''
76
- if thumb :
77
- thumb_string = '-thumb'
78
- image_name = image_id + thumb_string + '.' + self .file_ext
79
- return os .path .join (year , month , image_name )
80
-
81
87
def get_file_ext (self ):
82
88
'''Method to return the file extension, as determined by Pillow.
83
89
@@ -125,33 +131,69 @@ def save(self):
125
131
self .image_object .thumbnail (size , Image .HAMMING )
126
132
self .image_object .save (thumb_dest , ** save_parameters )
127
133
134
+ def get_file_info (self ):
135
+ return {
136
+ 'filename' : self .get_filename (self .image_path ),
137
+ 'url' : self .get_url (self .image_path ),
138
+ 'thumb_url' : self .get_url (self .thumb_path )
139
+ }
140
+
141
+
142
+ class LogUpload (BaseUpload ):
143
+ def __init__ (self , data ):
144
+ super ().__init__ ()
145
+ self .data = self .process_data (data )
146
+ self .file_path = self .get_file_path (self .year , self .month ,
147
+ self .file_id , 'json' )
148
+
149
+ def process_data (self , data ):
150
+ try :
151
+ return json .loads (data )
152
+ except ValueError :
153
+ abort (400 )
154
+
155
+ def get_url (self , file_path ):
156
+ return os .path .splitext (file_path )[0 ]
157
+
158
+ def save (self ):
159
+ file_dest = app .config ['UPLOADS_DEFAULT_DEST' ] + self .file_path
160
+ dest_dir = os .path .dirname (file_dest )
161
+
162
+ if not os .path .exists (dest_dir ):
163
+ os .makedirs (dest_dir )
164
+
165
+ with open (file_dest , 'w' , encoding = 'utf-8' ) as f :
166
+ json .dump (self .data , f , ensure_ascii = False )
167
+
168
+ def get_file_info (self ):
169
+ return {
170
+ 'url' : self .get_url (self .file_path )
171
+ }
172
+
128
173
129
174
@uploads .route ('/' , methods = ['POST' ])
130
175
def upload ():
131
- '''Endpoint to upload an image.
176
+ '''Endpoint to upload an image or a json with console logs .
132
177
133
- If the image asset passes validation, it's saved as:
178
+ If the file asset passes validation, it's saved as:
134
179
UPLOADS_DEFAULT_DEST + /year/month/random-uuid.ext
135
180
136
181
Returns a JSON string that contains the filename and url.
137
182
'''
138
- if 'image' in request .files and request .files ['image' ].filename :
139
- imagedata = request .files ['image' ]
140
- elif 'image' in request .form :
141
- imagedata = request .form ['image' ]
142
- else :
183
+ is_image , data = get_data_from_request (request )
184
+ if not data :
143
185
# We don't know what you're trying to do, but it ain't gonna work.
144
186
abort (501 )
145
187
146
188
try :
147
- upload = Upload (imagedata )
189
+ if is_image :
190
+ upload = ImageUpload (data )
191
+ else :
192
+ upload = LogUpload (data )
193
+
148
194
upload .save ()
149
- data = {
150
- 'filename' : upload .get_filename (upload .image_path ),
151
- 'url' : upload .get_url (upload .image_path ),
152
- 'thumb_url' : upload .get_url (upload .thumb_path )
153
- }
154
- return (json .dumps (data ), 201 , {'content-type' : JSON_MIME })
195
+ file_info = upload .get_file_info ()
196
+ return json .dumps (file_info ), 201 , {'content-type' : JSON_MIME }
155
197
except (TypeError , IOError ):
156
198
abort (415 )
157
199
except RequestEntityTooLarge :
0 commit comments