# HG changeset patch # User Björn Ricks # Date 1414489902 -3600 # Node ID e99cbb47eafb4b9d812ab865e7c7226826df2272 # Parent f270eaa7de8dc5eb11a03e7b73fe256c2734f633 Improve error handling by returning flask/werkzeug responses directly on errors diff -r f270eaa7de8d -r e99cbb47eafb odfcast/convert.py --- a/odfcast/convert.py Fri Oct 24 13:25:12 2014 +0200 +++ b/odfcast/convert.py Tue Oct 28 10:51:42 2014 +0100 @@ -10,11 +10,15 @@ from PyPDF2 import PdfFileMerger +from werkzeug.utils import escape + log = logging.getLogger(__name__) ALLOWED_FORMATS = ["pdf", "doc", "docx", "odt"] PDF_MIMETYPE = "application/pdf" +JSON_MIMETYPE = "application/json" +HTML_MIMETYPE = "text/html" MIMETYPES = { "odt": "application/vnd.oasis.opendocument.text", @@ -27,34 +31,68 @@ DEFAULT_MIMETYPE = "application/octet-stream" -class ErrorResponse(object): +class ErrorResponse(Response): - def __init__(self, title, details="", html_error_code=500): - self.title = title - self.details = details - self.html_error_code = html_error_code + BAD_REQUEST_ERROR_CODE = 400 - def __call__(self): + def __init__(self, title, error_code, details, + html_error_code=BAD_REQUEST_ERROR_CODE): + data, mime_type = self.get_response_data(title, error_code, details) + super(ErrorResponse, self).__init__(response=data, mimetype=mime_type, + status=html_error_code) + + def json(self, title, error_code, details): + return json.dumps({ + "error": title, + "error_code": error_code, + "details": details, + }), JSON_MIMETYPE + + def html(self, title, error_code, details): + data = "" + return ( + u'\n' + u'%(code)s %(name)s\n' + u'

%(name)s

\n' + u'%(details)s\n' + ) % { + "code": error_code, + "name": escape(title), + "details": escape(details), + } + return data, HTML_MIMETYPE + + def get_response_data(self, title, error_code, details): if self.is_wants_json(): - return self.json() - else: - return self.html() - - def json(self): - return json.dumps({ - "error": self.title, - "details": self.details - }), self.html_error_code - - def html(self): - return self.title, self.html_error_code + return self.json(title, error_code, details) + return self.html(title, error_code, details) def is_wants_json(self): - best = request.accept_mimetypes.best_match(['application/json', - 'text/html']) - return best == 'application/json' and \ + best = request.accept_mimetypes.best_match([JSON_MIMETYPE, + HTML_MIMETYPE]) + return best == JSON_MIMETYPE and \ request.accept_mimetypes[best] > \ - request.accept_mimetypes['text/html'] + request.accept_mimetypes[HTML_MIMETYPE] + + +class TemplateErrorResponse(ErrorResponse): + + TEMPLATE_ERROR_CODE = 100 + + def __init__(self, details, error_code=TEMPLATE_ERROR_CODE): + super(TemplateErrorResponse, self).__init__( + title="TemplateError", error_code=error_code, details=details, + html_error_code=500) + + +class ConversionErrorResponse(ErrorResponse): + + CONVERSION_ERROR_CODE = 200 + + def __init__(self, details, error_code=CONVERSION_ERROR_CODE): + super(TemplateErrorResponse, self).__init__( + title="ConversionError", error_code=error_code, details=details, + html_error_code=500) class ConvertView(MethodView): @@ -73,15 +111,17 @@ def post(self): ffile = request.files['file'] if not ffile.filename: - error = ErrorResponse("Please upload a file for conversion", - html_error_code=401) - return error() + return ErrorResponse( + "Upload file missing", error_code=101, + details="Please upload a file for conversion", + html_error_code=400) fformat = request.form['format'] if not self.is_format_supported(fformat): - error = ErrorResponse("Format %s not allowed" % fformat, - html_error_code=401) - return error() + return ErrorResponse( + "Invalid format", error_code=102, + details="Format %s not allowed" % fformat, + html_error_code=400) datadict = self.get_datadict() @@ -98,18 +138,14 @@ outfile = tfile except Exception, e: log.exception("Template error") - error = ErrorResponse( - "Template error", details=str(e), html_error_code=500) - return error() + return TemplateErrorResponse(details=str(e)) if fformat != "odt": try: outfile = self.convert(outfile, fformat) except Exception, e: log.exception("Conversion error") - error = ErrorResponse( - "Conversion error", details=str(e), html_error_code=500) - return error() + return ConversionErrorResponse(details=str(e)) return Response(outfile, mimetype=mimetype)