bjoern@0: # -*- coding: utf-8 -*- bjoern@0: bjoern@29: import logging bjoern@0: import tempfile bjoern@0: bjoern@16: from flask import request, Response, json, render_template bjoern@0: from flask.views import MethodView bjoern@0: bjoern@4: from py3o.template import Template bjoern@4: bjoern@19: from PyPDF2 import PdfFileMerger bjoern@19: bjoern@47: from werkzeug.utils import escape bjoern@47: bjoern@29: log = logging.getLogger(__name__) bjoern@19: bjoern@0: ALLOWED_FORMATS = ["pdf", "doc", "docx", "odt"] bjoern@0: bjoern@19: PDF_MIMETYPE = "application/pdf" bjoern@47: JSON_MIMETYPE = "application/json" bjoern@47: HTML_MIMETYPE = "text/html" bjoern@19: bjoern@0: MIMETYPES = { bjoern@0: "odt": "application/vnd.oasis.opendocument.text", bjoern@0: "doc": "application/msword", bjoern@0: "docx": "application/vnd.openxmlformats-officedocument" bjoern@0: ".wordprocessingml.document", bjoern@19: "pdf": PDF_MIMETYPE, bjoern@0: } bjoern@0: bjoern@0: DEFAULT_MIMETYPE = "application/octet-stream" bjoern@0: bjoern@0: bjoern@47: class ErrorResponse(Response): bjoern@42: bjoern@47: BAD_REQUEST_ERROR_CODE = 400 bjoern@42: bjoern@47: def __init__(self, title, error_code, details, bjoern@47: html_error_code=BAD_REQUEST_ERROR_CODE): bjoern@47: data, mime_type = self.get_response_data(title, error_code, details) bjoern@47: super(ErrorResponse, self).__init__(response=data, mimetype=mime_type, bjoern@47: status=html_error_code) bjoern@47: bjoern@47: def json(self, title, error_code, details): bjoern@47: return json.dumps({ bjoern@47: "error": title, bjoern@47: "error_code": error_code, bjoern@47: "details": details, bjoern@47: }), JSON_MIMETYPE bjoern@47: bjoern@47: def html(self, title, error_code, details): bjoern@47: data = "" bjoern@47: return ( bjoern@47: u'\n' bjoern@47: u'%(code)s %(name)s\n' bjoern@47: u'

%(name)s

\n' bjoern@47: u'%(details)s\n' bjoern@47: ) % { bjoern@47: "code": error_code, bjoern@47: "name": escape(title), bjoern@47: "details": escape(details), bjoern@47: } bjoern@47: return data, HTML_MIMETYPE bjoern@47: bjoern@47: def get_response_data(self, title, error_code, details): bjoern@42: if self.is_wants_json(): bjoern@47: return self.json(title, error_code, details) bjoern@47: return self.html(title, error_code, details) bjoern@42: bjoern@42: def is_wants_json(self): bjoern@47: best = request.accept_mimetypes.best_match([JSON_MIMETYPE, bjoern@47: HTML_MIMETYPE]) bjoern@47: return best == JSON_MIMETYPE and \ bjoern@42: request.accept_mimetypes[best] > \ bjoern@47: request.accept_mimetypes[HTML_MIMETYPE] bjoern@47: bjoern@47: bjoern@47: class TemplateErrorResponse(ErrorResponse): bjoern@47: bjoern@47: TEMPLATE_ERROR_CODE = 100 bjoern@47: bjoern@47: def __init__(self, details, error_code=TEMPLATE_ERROR_CODE): bjoern@47: super(TemplateErrorResponse, self).__init__( bjoern@47: title="TemplateError", error_code=error_code, details=details, bjoern@47: html_error_code=500) bjoern@47: bjoern@47: bjoern@47: class ConversionErrorResponse(ErrorResponse): bjoern@47: bjoern@47: CONVERSION_ERROR_CODE = 200 bjoern@47: bjoern@47: def __init__(self, details, error_code=CONVERSION_ERROR_CODE): bjoern@47: super(TemplateErrorResponse, self).__init__( bjoern@47: title="ConversionError", error_code=error_code, details=details, bjoern@47: html_error_code=500) bjoern@42: bjoern@42: bjoern@0: class ConvertView(MethodView): bjoern@0: bjoern@0: def __init__(self, pyuno_driver_name="", hostname="localhost", port=2001): bjoern@0: driver_module = self._load_driver_module(pyuno_driver_name) bjoern@0: self.convertor = driver_module.Convertor(hostname, port) bjoern@0: bjoern@0: def _load_driver_module(self, pyuno_driver_name): bjoern@0: return __import__(pyuno_driver_name, globals(), locals(), bjoern@0: ["Convertor"]) bjoern@0: bjoern@3: def is_format_supported(self, fformat): bjoern@3: return fformat and fformat.lower() in ALLOWED_FORMATS bjoern@0: bjoern@3: def post(self): bjoern@3: ffile = request.files['file'] bjoern@29: if not ffile.filename: bjoern@47: return ErrorResponse( bjoern@47: "Upload file missing", error_code=101, bjoern@47: details="Please upload a file for conversion", bjoern@47: html_error_code=400) bjoern@29: bjoern@3: fformat = request.form['format'] bjoern@3: if not self.is_format_supported(fformat): bjoern@47: return ErrorResponse( bjoern@47: "Invalid format", error_code=102, bjoern@47: details="Format %s not allowed" % fformat, bjoern@47: html_error_code=400) bjoern@3: bjoern@30: datadict = self.get_datadict() bjoern@30: bjoern@29: mimetype = self.get_mimetype_for_format(fformat) bjoern@29: bjoern@30: outfile = self.save_form_file(ffile) bjoern@30: bjoern@30: if datadict: bjoern@31: try: bjoern@31: tfile = tempfile.NamedTemporaryFile() bjoern@42: t = Template(outfile, tfile, ignore_undefined_variables=True) bjoern@31: t.render(datadict) bjoern@31: outfile.close() bjoern@31: outfile = tfile bjoern@42: except Exception, e: bjoern@41: log.exception("Template error") bjoern@47: return TemplateErrorResponse(details=str(e)) bjoern@30: bjoern@32: if fformat != "odt": bjoern@30: try: bjoern@30: outfile = self.convert(outfile, fformat) bjoern@42: except Exception, e: bjoern@30: log.exception("Conversion error") bjoern@47: return ConversionErrorResponse(details=str(e)) bjoern@29: bjoern@0: return Response(outfile, mimetype=mimetype) bjoern@0: bjoern@16: def get(self): bjoern@16: return render_template("convert.html") bjoern@16: bjoern@3: def save_form_file(self, infile): bjoern@33: outfile = tempfile.NamedTemporaryFile() bjoern@30: infile.save(outfile) bjoern@30: infile.close() bjoern@33: outfile.seek(0) bjoern@3: return outfile bjoern@3: bjoern@3: def convert(self, infile, fformat): bjoern@0: outfile = tempfile.NamedTemporaryFile() bjoern@0: bjoern@3: self.convertor.convert(infile.name, outfile.name, fformat) bjoern@0: bjoern@0: infile.close() bjoern@0: return outfile bjoern@0: bjoern@3: def get_mimetype_for_format(self, fformat): bjoern@3: return MIMETYPES.get(fformat, DEFAULT_MIMETYPE) bjoern@4: bjoern@4: def get_datadict(self): bjoern@34: vars = request.form.get('datadict') bjoern@30: if not vars: bjoern@30: return None bjoern@4: return json.loads(vars) bjoern@18: bjoern@19: bjoern@19: class MergeView(MethodView): bjoern@19: bjoern@19: def get(self): bjoern@19: return render_template("merge.html") bjoern@19: bjoern@19: def post(self): bjoern@19: merger = PdfFileMerger() bjoern@19: ffiles = request.files.getlist('files') bjoern@19: bjoern@19: for ffile in ffiles: bjoern@19: merger.append(ffile) bjoern@19: bjoern@19: outfile = tempfile.NamedTemporaryFile() bjoern@19: bjoern@19: merger.write(outfile.name) bjoern@19: bjoern@19: merger.close() bjoern@19: return Response(outfile, mimetype=PDF_MIMETYPE) bjoern@22: bjoern@22: bjoern@22: class TemplateView(MethodView): bjoern@22: bjoern@22: template_name = "" bjoern@22: bjoern@22: def __init__(self, template_name=None): bjoern@22: if template_name: bjoern@22: self.template_name = template_name bjoern@22: bjoern@22: def get_template_name(self): bjoern@22: return self.template_name bjoern@22: bjoern@22: def get(self): bjoern@22: return render_template(self.get_template_name())