diff options
| author | Christophe Simonis <chs@odoo.com> | 2016-08-26 14:57:43 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2016-08-26 14:57:43 +0200 |
| commit | 717a4a51a5bf03f853aa2e4c229b929e2b87ea2d (patch) | |
| tree | bc0a9d2c758e7055cb0cd23f12c1c33b04b2a872 /openerp | |
| parent | 438a3742e238ba074b880d5d563f2c7151a767c6 (diff) | |
| parent | 7a4116cd03c56d694a1b6d39a523ac1cc3306f52 (diff) | |
[MERGE] forward port branch saas-10 up to 7a4116c
Diffstat (limited to 'openerp')
| -rw-r--r-- | openerp/addons/base/ir/ir_http.py | 18 | ||||
| -rw-r--r-- | openerp/addons/base/res/res_users.py | 3 | ||||
| -rw-r--r-- | openerp/addons/base/tests/__init__.py | 4 | ||||
| -rw-r--r-- | openerp/addons/base/tests/test_ir_http.py | 81 | ||||
| -rw-r--r-- | openerp/addons/base/tests/test_mimetypes.py | 52 | ||||
| -rw-r--r-- | openerp/addons/base/tests/test_uninstall.py | 2 | ||||
| -rw-r--r-- | openerp/http.py | 13 | ||||
| -rw-r--r-- | openerp/tools/mimetypes.py | 7 |
8 files changed, 160 insertions, 20 deletions
diff --git a/openerp/addons/base/ir/ir_http.py b/openerp/addons/base/ir/ir_http.py index 6e6cb250312..4907ce131a7 100644 --- a/openerp/addons/base/ir/ir_http.py +++ b/openerp/addons/base/ir/ir_http.py @@ -21,7 +21,8 @@ import werkzeug.utils import odoo from odoo import api, http, models, tools, SUPERUSER_ID from odoo.exceptions import AccessDenied, AccessError -from odoo.http import request, STATIC_CACHE +from odoo.http import request, STATIC_CACHE, content_disposition +from odoo.tools.mimetypes import guess_mimetype from odoo.modules.module import get_resource_path, get_module_path _logger = logging.getLogger(__name__) @@ -210,16 +211,7 @@ class IrHttp(models.AbstractModel): return self._routing_map def content_disposition(self, filename): - filename = tools.ustr(filename) - escaped = urllib2.quote(filename.encode('utf8')) - browser = request.httprequest.user_agent.browser - version = int((request.httprequest.user_agent.version or '0').split('.')[0]) - if browser == 'msie' and version < 9: - return "attachment; filename=%s" % escaped - elif browser == 'safari' and version < 537: - return u"attachment; filename=%s" % filename.encode('ascii', 'replace') - else: - return "attachment; filename*=UTF-8''%s" % escaped + return content_disposition(filename) def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', env=None): """ Get file, attachment or downloadable content @@ -305,7 +297,8 @@ class IrHttp(models.AbstractModel): attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1) mimetype = attach_mimetype and attach_mimetype[0]['mimetype'] if not mimetype: - mimetype = default_mimetype + mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype) + headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')] # cache @@ -318,7 +311,6 @@ class IrHttp(models.AbstractModel): # content-disposition default name if download: headers.append(('Content-Disposition', self.content_disposition(filename))) - return (status, headers, content) diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 775384ccbb7..73b909607d3 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -678,8 +678,7 @@ class GroupsView(models.Model): @api.multi def write(self, values): res = super(GroupsView, self).write(values) - if 'category_id' in values: - self._update_user_groups_view() + self._update_user_groups_view() # ir_values.get_actions() depends on action records self.env['ir.values'].clear_caches() return res diff --git a/openerp/addons/base/tests/__init__.py b/openerp/addons/base/tests/__init__.py index e9414be9011..2325c11aa8e 100644 --- a/openerp/addons/base/tests/__init__.py +++ b/openerp/addons/base/tests/__init__.py @@ -7,12 +7,14 @@ import test_expression import test_func import test_ir_actions import test_ir_attachment +import test_ir_http import test_ir_filters import test_ir_sequence import test_ir_sequence_date_range import test_ir_values import test_mail import test_menu +import test_mimetypes import test_orm import test_ormcache import test_osv @@ -21,7 +23,7 @@ import test_res_config import test_res_lang import test_search import test_translate -#import test_uninstall +#import test_uninstall # loop import test_user_has_group import test_view_validation import test_views diff --git a/openerp/addons/base/tests/test_ir_http.py b/openerp/addons/base/tests/test_ir_http.py new file mode 100644 index 00000000000..649cd069816 --- /dev/null +++ b/openerp/addons/base/tests/test_ir_http.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +from openerp.tests import common +import openerp + +GIF = "R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBADs=" + + +class test_ir_http_mimetype(common.TransactionCase): + + def test_ir_http_mimetype_attachment(self): + """ Test mimetype for attachment """ + attachment = self.env['ir.attachment'].create({ + 'datas': GIF, + 'name': 'Test mimetype gif', + 'datas_fname': 'file.gif'}) + + status, headers, content = self.env['ir.http'].binary_content( + id=attachment.id, + mimetype=None, + default_mimetype='application/octet-stream', + env=self.env + ) + mimetype = dict(headers).get('Content-Type') + self.assertEqual(mimetype, 'image/gif') + + def test_ir_http_mimetype_attachment_name(self): + """ Test mimetype for attachment with bad name""" + attachment = self.env['ir.attachment'].create({ + 'datas': GIF, + 'name': 'Test mimetype gif with png name', + 'datas_fname': 'file.png'}) + + status, headers, content = self.env['ir.http'].binary_content( + id=attachment.id, + mimetype=None, + default_mimetype='application/octet-stream', + env=self.env + ) + mimetype = dict(headers).get('Content-Type') + # TODO: fix and change it in master, should be image/gif + self.assertEqual(mimetype, 'image/png') + + def test_ir_http_mimetype_basic_field(self): + """ Test mimetype for classic field """ + partner = self.env['res.partner'].create({ + 'image': GIF, + 'name': 'Test mimetype basic field', + }) + + status, headers, content = self.env['ir.http'].binary_content( + model='res.partner', + id=partner.id, + field='image', + default_mimetype='application/octet-stream', + env=self.env + ) + mimetype = dict(headers).get('Content-Type') + self.assertEqual(mimetype, 'image/gif') + + def test_ir_http_mimetype_computed_field(self): + """ Test mimetype for computed field wich resize picture""" + prop = self.env['ir.property'].create({ + 'fields_id': self.env['ir.model.fields'].search([], limit=1).id, + 'name': "Property binary", + 'value_binary': GIF, + 'type': 'binary', + }) + + resized = openerp.tools.image_get_resized_images(prop.value_binary, return_big=True, avoid_resize_medium=True)['image_small'] + # Simul computed field which resize and that is not attachement=True (E.G. on product) + prop.write({'value_binary': resized}) + status, headers, content = self.env['ir.http'].binary_content( + model='ir.property', + id=prop.id, + field='value_binary', + default_mimetype='application/octet-stream', + env=self.env + ) + mimetype = dict(headers).get('Content-Type') + self.assertEqual(mimetype, 'image/gif') diff --git a/openerp/addons/base/tests/test_mimetypes.py b/openerp/addons/base/tests/test_mimetypes.py new file mode 100644 index 00000000000..0d3ce6b71fc --- /dev/null +++ b/openerp/addons/base/tests/test_mimetypes.py @@ -0,0 +1,52 @@ +import base64 +import unittest + +from openerp.tools.mimetypes import guess_mimetype + +PNG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQI12P4//8/AAX+Av7czFnnAAAAAElFTkSuQmCC' +GIF = "R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBADs=" +BMP = """Qk1+AAAAAAAAAHoAAABsAAAAAQAAAAEAAAABABgAAAAAAAQAAAATCwAAEwsAAAAAAAAAAAAAQkdScwAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAD///8A""" +JPG = """/9j/4AAQSkZJRgABAQEASABIAAD//gATQ3JlYXRlZCB3aXRoIEdJTVD/2wBDAP +//////////////////////////////////////////////////////////////////////////////////////2wBDAf/////// +///////////////////////////////////////////////////////////////////////////////wgARCAABAAEDAREAAhEB +AxEB/8QAFAABAAAAAAAAAAAAAAAAAAAAAv/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAUf/xAAUEAEAAAAAAAA +AAAAAAAAAAAAA/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/AX//xAAUEQEAAAAAAAAAAAAAAAAAAA +AA/9oACAECAQE/AX//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAY/An//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBA +AE/IX//2gAMAwEAAgADAAAAEB//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/EH//xAAUEQEAAAAAAAAAAAAAAAAAAAAA +/9oACAECAQE/EH//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/EH//2Q==""" + + +class test_guess_mimetype(unittest.TestCase): + + def test_default_mimetype_empty(self): + mimetype = guess_mimetype('') + self.assertEqual(mimetype, 'application/octet-stream') + + def test_default_mimetype(self): + mimetype = guess_mimetype('', default='test') + self.assertEqual(mimetype, 'test') + + def test_mimetype_png(self): + content = base64.b64decode(PNG) + mimetype = guess_mimetype(content, default='test') + self.assertEqual(mimetype, 'image/png') + + def test_mimetype_bmp(self): + content = base64.b64decode(BMP) + mimetype = guess_mimetype(content, default='test') + self.assertEqual(mimetype, 'image/bmp') + + def test_mimetype_jpg(self): + content = base64.b64decode(JPG) + mimetype = guess_mimetype(content, default='test') + self.assertEqual(mimetype, 'image/jpeg') + + def test_mimetype_gif(self): + content = base64.b64decode(GIF) + mimetype = guess_mimetype(content, default='test') + self.assertEqual(mimetype, 'image/gif') + + +if __name__ == '__main__': + unittest.main() diff --git a/openerp/addons/base/tests/test_uninstall.py b/openerp/addons/base/tests/test_uninstall.py index 8bb658d61ba..a99240d703b 100644 --- a/openerp/addons/base/tests/test_uninstall.py +++ b/openerp/addons/base/tests/test_uninstall.py @@ -4,7 +4,7 @@ import unittest import openerp from openerp import SUPERUSER_ID -import common +from openerp.tests import common ADMIN_USER_ID = common.ADMIN_USER_ID diff --git a/openerp/http.py b/openerp/http.py index d837131d52d..45db589aa28 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -20,6 +20,7 @@ import sys import threading import time import traceback +import urllib2 import urlparse import warnings from zlib import adler32 @@ -1809,6 +1810,18 @@ def send_file(filepath_or_fp, mimetype=None, as_attachment=False, filename=None, rv.headers.pop('x-sendfile', None) return rv +def content_disposition(filename): + filename = openerp.tools.ustr(filename) + escaped = urllib2.quote(filename.encode('utf8')) + browser = request.httprequest.user_agent.browser + version = int((request.httprequest.user_agent.version or '0').split('.')[0]) + if browser == 'msie' and version < 9: + return "attachment; filename=%s" % escaped + elif browser == 'safari' and version < 537: + return u"attachment; filename=%s" % filename.encode('ascii', 'replace') + else: + return "attachment; filename*=UTF-8''%s" % escaped + #---------------------------------------------------------- # RPC controller #---------------------------------------------------------- diff --git a/openerp/tools/mimetypes.py b/openerp/tools/mimetypes.py index cf5a9debc90..581dcb27bd6 100644 --- a/openerp/tools/mimetypes.py +++ b/openerp/tools/mimetypes.py @@ -103,10 +103,11 @@ _Entry = collections.namedtuple('_Entry', ['mimetype', 'signatures', 'discrimina _mime_mappings = ( # pdf _Entry('application/pdf', ['%PDF'], []), - # jpg, jpeg, png, gif + # jpg, jpeg, png, gif, bmp _Entry('image/jpeg', ['\xFF\xD8\xFF\xE0', '\xFF\xD8\xFF\xE2', '\xFF\xD8\xFF\xE3', '\xFF\xD8\xFF\xE1'], []), _Entry('image/png', ['\x89PNG\r\n\x1A\n'], []), _Entry('image/gif', ['GIF87a', 'GIF89a'], []), + _Entry('image/bmp', ['BM'], []), # OLECF files in general (Word, Excel, PPT, default to word because why not?) _Entry('application/msword', ['\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', '\x0D\x44\x4F\x43'], [ _check_olecf @@ -114,7 +115,7 @@ _mime_mappings = ( # zip, but will include jar, odt, ods, odp, docx, xlsx, pptx, apk _Entry('application/zip', ['PK\x03\x04'], [_check_ooxml, _check_open_container_format]), ) -def guess_mimetype(bin_data): +def guess_mimetype(bin_data, default='application/octet-stream'): """ Attempts to guess the mime type of the provided binary data, similar to but significantly more limited than libmagic @@ -140,7 +141,7 @@ def guess_mimetype(bin_data): # if no discriminant or no discriminant matches, return # primary mime type return entry.mimetype - return 'application/octet-stream' + return default try: |
