comparison odfcast/convert.py @ 47:e99cbb47eafb

Improve error handling by returning flask/werkzeug responses directly on errors
author Björn Ricks <bjoern.ricks@intevation.de>
date Tue, 28 Oct 2014 10:51:42 +0100
parents 6d511e93a331
children 64f3e3a28bd4
comparison
equal deleted inserted replaced
46:f270eaa7de8d 47:e99cbb47eafb
8 8
9 from py3o.template import Template 9 from py3o.template import Template
10 10
11 from PyPDF2 import PdfFileMerger 11 from PyPDF2 import PdfFileMerger
12 12
13 from werkzeug.utils import escape
14
13 log = logging.getLogger(__name__) 15 log = logging.getLogger(__name__)
14 16
15 ALLOWED_FORMATS = ["pdf", "doc", "docx", "odt"] 17 ALLOWED_FORMATS = ["pdf", "doc", "docx", "odt"]
16 18
17 PDF_MIMETYPE = "application/pdf" 19 PDF_MIMETYPE = "application/pdf"
20 JSON_MIMETYPE = "application/json"
21 HTML_MIMETYPE = "text/html"
18 22
19 MIMETYPES = { 23 MIMETYPES = {
20 "odt": "application/vnd.oasis.opendocument.text", 24 "odt": "application/vnd.oasis.opendocument.text",
21 "doc": "application/msword", 25 "doc": "application/msword",
22 "docx": "application/vnd.openxmlformats-officedocument" 26 "docx": "application/vnd.openxmlformats-officedocument"
25 } 29 }
26 30
27 DEFAULT_MIMETYPE = "application/octet-stream" 31 DEFAULT_MIMETYPE = "application/octet-stream"
28 32
29 33
30 class ErrorResponse(object): 34 class ErrorResponse(Response):
31 35
32 def __init__(self, title, details="", html_error_code=500): 36 BAD_REQUEST_ERROR_CODE = 400
33 self.title = title 37
34 self.details = details 38 def __init__(self, title, error_code, details,
35 self.html_error_code = html_error_code 39 html_error_code=BAD_REQUEST_ERROR_CODE):
36 40 data, mime_type = self.get_response_data(title, error_code, details)
37 def __call__(self): 41 super(ErrorResponse, self).__init__(response=data, mimetype=mime_type,
42 status=html_error_code)
43
44 def json(self, title, error_code, details):
45 return json.dumps({
46 "error": title,
47 "error_code": error_code,
48 "details": details,
49 }), JSON_MIMETYPE
50
51 def html(self, title, error_code, details):
52 data = ""
53 return (
54 u'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n'
55 u'<title>%(code)s %(name)s</title>\n'
56 u'<h1>%(name)s</h1>\n'
57 u'%(details)s\n'
58 ) % {
59 "code": error_code,
60 "name": escape(title),
61 "details": escape(details),
62 }
63 return data, HTML_MIMETYPE
64
65 def get_response_data(self, title, error_code, details):
38 if self.is_wants_json(): 66 if self.is_wants_json():
39 return self.json() 67 return self.json(title, error_code, details)
40 else: 68 return self.html(title, error_code, details)
41 return self.html()
42
43 def json(self):
44 return json.dumps({
45 "error": self.title,
46 "details": self.details
47 }), self.html_error_code
48
49 def html(self):
50 return self.title, self.html_error_code
51 69
52 def is_wants_json(self): 70 def is_wants_json(self):
53 best = request.accept_mimetypes.best_match(['application/json', 71 best = request.accept_mimetypes.best_match([JSON_MIMETYPE,
54 'text/html']) 72 HTML_MIMETYPE])
55 return best == 'application/json' and \ 73 return best == JSON_MIMETYPE and \
56 request.accept_mimetypes[best] > \ 74 request.accept_mimetypes[best] > \
57 request.accept_mimetypes['text/html'] 75 request.accept_mimetypes[HTML_MIMETYPE]
76
77
78 class TemplateErrorResponse(ErrorResponse):
79
80 TEMPLATE_ERROR_CODE = 100
81
82 def __init__(self, details, error_code=TEMPLATE_ERROR_CODE):
83 super(TemplateErrorResponse, self).__init__(
84 title="TemplateError", error_code=error_code, details=details,
85 html_error_code=500)
86
87
88 class ConversionErrorResponse(ErrorResponse):
89
90 CONVERSION_ERROR_CODE = 200
91
92 def __init__(self, details, error_code=CONVERSION_ERROR_CODE):
93 super(TemplateErrorResponse, self).__init__(
94 title="ConversionError", error_code=error_code, details=details,
95 html_error_code=500)
58 96
59 97
60 class ConvertView(MethodView): 98 class ConvertView(MethodView):
61 99
62 def __init__(self, pyuno_driver_name="", hostname="localhost", port=2001): 100 def __init__(self, pyuno_driver_name="", hostname="localhost", port=2001):
71 return fformat and fformat.lower() in ALLOWED_FORMATS 109 return fformat and fformat.lower() in ALLOWED_FORMATS
72 110
73 def post(self): 111 def post(self):
74 ffile = request.files['file'] 112 ffile = request.files['file']
75 if not ffile.filename: 113 if not ffile.filename:
76 error = ErrorResponse("Please upload a file for conversion", 114 return ErrorResponse(
77 html_error_code=401) 115 "Upload file missing", error_code=101,
78 return error() 116 details="Please upload a file for conversion",
117 html_error_code=400)
79 118
80 fformat = request.form['format'] 119 fformat = request.form['format']
81 if not self.is_format_supported(fformat): 120 if not self.is_format_supported(fformat):
82 error = ErrorResponse("Format %s not allowed" % fformat, 121 return ErrorResponse(
83 html_error_code=401) 122 "Invalid format", error_code=102,
84 return error() 123 details="Format %s not allowed" % fformat,
124 html_error_code=400)
85 125
86 datadict = self.get_datadict() 126 datadict = self.get_datadict()
87 127
88 mimetype = self.get_mimetype_for_format(fformat) 128 mimetype = self.get_mimetype_for_format(fformat)
89 129
96 t.render(datadict) 136 t.render(datadict)
97 outfile.close() 137 outfile.close()
98 outfile = tfile 138 outfile = tfile
99 except Exception, e: 139 except Exception, e:
100 log.exception("Template error") 140 log.exception("Template error")
101 error = ErrorResponse( 141 return TemplateErrorResponse(details=str(e))
102 "Template error", details=str(e), html_error_code=500)
103 return error()
104 142
105 if fformat != "odt": 143 if fformat != "odt":
106 try: 144 try:
107 outfile = self.convert(outfile, fformat) 145 outfile = self.convert(outfile, fformat)
108 except Exception, e: 146 except Exception, e:
109 log.exception("Conversion error") 147 log.exception("Conversion error")
110 error = ErrorResponse( 148 return ConversionErrorResponse(details=str(e))
111 "Conversion error", details=str(e), html_error_code=500)
112 return error()
113 149
114 return Response(outfile, mimetype=mimetype) 150 return Response(outfile, mimetype=mimetype)
115 151
116 def get(self): 152 def get(self):
117 return render_template("convert.html") 153 return render_template("convert.html")
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)