You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

149 lines
6.2 KiB

# -*- coding: utf-8 -*-
###################################################################################
#
# Copyright (C) 2017 MuK IT GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###################################################################################
import os
import sys
import json
import uuid
import base64
import urllib
import urllib2
import logging
import tempfile
import urlparse
import cStringIO
import mimetypes
import collections
import werkzeug.exceptions
from contextlib import closing
from odoo import _
from odoo import tools
from odoo import http
from odoo.http import request
from odoo.http import Response
_logger = logging.getLogger(__name__)
try:
import requests
except ImportError:
_logger.warn('Cannot `import requests`.')
try:
from cachetools import TTLCache
pdf_cache = TTLCache(maxsize=25, ttl=1200)
except ImportError:
_logger.warn('Cannot `import cachetools`.')
try:
import pdfconv
except ImportError:
_logger.warn('Cannot `import pdfconv`.')
class ExportAttachmentController(http.Controller):
@http.route('/web/export/pdf/check/filename', auth="user", type='http')
def check_filename(self, filename, **kw):
return self.check_mimetype(mimetypes.guess_type(urllib.pathname2url(filename))[0])
@http.route('/web/export/pdf/check/mimetype', auth="user", type='http')
def check_mimetype(self, mimetype, **kw):
if mimetype in ['application/msword',
'application/ms-word',
'application/vnd.ms-word.document.macroEnabled.12',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.oasis.opendocument.text',
'application/vnd.mspowerpoint',
'application/vnd.ms-powerpoint',
'application/vnd.ms-powerpoint.addin.macroEnabled.12',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.msexcel',
'application/vnd.ms-excel',
'application/vnd.ms-excel.sheet.macroEnabled.12',
'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.oasis.opendocument.spreadsheet']:
return Response(json.dumps(True), mimetype='application/json;charset=utf-8')
else:
return Response(json.dumps(False), mimetype='application/json;charset=utf-8')
@http.route('/web/export/pdf', auth="user", type='http')
def export(self, url, filename=None, force_compute=False, **kw):
try:
response = pdf_cache[url] if pdf_cache and not force_compute else None
except KeyError:
response = None
if not response:
return self._get_response(url, filename)
return response
def _get_response(self, url, filename):
if not bool(urlparse.urlparse(url).netloc):
method, params = self._get_route(url)
response = method(**params)
if not response.status_code == 200:
return self._make_error_response(response.status_code,response.description if hasattr(response, 'description') else _("Unknown Error"))
else:
content_type = response.headers['content-type']
data = response.data
else:
try:
response = requests.get(url)
content_type = response.headers['content-type']
data = response.content
except requests.exceptions.RequestException as exception:
return self._make_error_response(exception.response.status_code, exception.response.reason or _("Unknown Error"))
try:
response = self._make_pdf_response(pdfconv.converter.convert_binary2pdf(data, content_type, None, format='binary'), filename or uuid.uuid4())
pdf_cache[url] = response
return response
except KeyError:
return werkzeug.exceptions.UnsupportedMediaType(_("The file couldn't be converted. Unsupported mine type."))
except (ImportError, IOError, WindowsError) as error:
_logger.error(error)
return werkzeug.exceptions.InternalServerError(_("An error occurred during the process. Please contact your system administrator."))
def _get_route(self, url):
url_parts = url.split('?')
path = url_parts[0]
query_string = url_parts[1] if len(url_parts) > 1 else None
router = request.httprequest.app.get_db_router(request.db).bind('')
match = router.match(path, query_args=query_string)
method = router.match(path, query_args=query_string)[0]
params = dict(urlparse.parse_qsl(query_string))
if len(match) > 1:
params.update(match[1])
return method, params
def _make_error_response(self, status, message):
exception = werkzeug.exceptions.HTTPException()
exception.code = status
exception.description = message
return exception
def _make_pdf_response(self, file, filename):
headers = [('Content-Type', 'application/pdf'),
('Content-Disposition', 'attachment;filename={};'.format(filename)),
('Content-Length', len(file))]
return request.make_response(file, headers)