diff --git a/ir_attachment_url/README.rst b/ir_attachment_url/README.rst index a8e849f006..61f379d596 100644 --- a/ir_attachment_url/README.rst +++ b/ir_attachment_url/README.rst @@ -18,10 +18,10 @@ Sponsors Further information =================== -HTML Description: https://apps.odoo.com/apps/modules/10.0/ir_attachment_url/ +HTML Description: https://apps.odoo.com/apps/modules/12.0/ir_attachment_url/ Usage instructions: ``_ Changelog: ``_ -Tested on Odoo 10.0 f05e8655ee4ee7205c67006ca5a8cb30ed445c81 +Tested on Odoo 12.0 e774b2cb1c29fdd407aedc1f5c959d9725d2b514 diff --git a/ir_attachment_url/__manifest__.py b/ir_attachment_url/__manifest__.py index 95ead498c4..cd3a4f80a8 100644 --- a/ir_attachment_url/__manifest__.py +++ b/ir_attachment_url/__manifest__.py @@ -3,11 +3,11 @@ "summary": """Use attachment URL and upload data to external storage""", "category": "Tools", "images": [], - "version": "11.0.1.1.6", + "version": "12.0.1.1.6", "application": False, "author": "IT-Projects LLC, Ildar Nasyrov", - "website": "https://it-projects.info", + "website": "https://apps.odoo.com/apps/modules/12.0/ir_attachment_url/", "license": "AGPL-3", "price": 30.00, "currency": "EUR", @@ -31,5 +31,5 @@ "post_init_hook": None, "auto_install": False, - "installable": False, + "installable": True, } diff --git a/ir_attachment_url/doc/index.rst b/ir_attachment_url/doc/index.rst index f44d4642e4..70828e63de 100644 --- a/ir_attachment_url/doc/index.rst +++ b/ir_attachment_url/doc/index.rst @@ -27,9 +27,9 @@ Odoo parameters Usage ===== -* Go to Sales >> Products menu +* Go to Sales >> Products >> Products * Open a product * Upload image to this product or specify image URL * Save the changes -* Go to Settings >> Database Structure >> Attachments menu +* Go to Settings >> Technical >> Database Structure >> Attachments * See related attachment form that contains URL of the image diff --git a/ir_attachment_url/models/binary_fields.py b/ir_attachment_url/models/binary_fields.py index 5198252aa7..21af1cae75 100644 --- a/ir_attachment_url/models/binary_fields.py +++ b/ir_attachment_url/models/binary_fields.py @@ -5,7 +5,7 @@ class Binary(fields.Binary): - def write(self, records, value, create=False): + def write(self, records, value): domain = [ ('res_model', '=', records._name), ('res_field', '=', self.name), @@ -40,7 +40,7 @@ def write(self, records, value, create=False): else: atts.unlink() else: - super(Binary, self).write(records, value, create=create) + super(Binary, self).write(records, value) fields.Binary = Binary diff --git a/ir_attachment_url/models/image.py b/ir_attachment_url/models/image.py index 5ab32bc32e..83188c5f79 100644 --- a/ir_attachment_url/models/image.py +++ b/ir_attachment_url/models/image.py @@ -5,8 +5,11 @@ super_image_resize_images = tools.image_resize_images -def updated_image_resize_images(vals, big_name='image', medium_name='image_medium', small_name='image_small'): +def updated_image_resize_images(vals, big_name='image', medium_name='image_medium', small_name='image_small', sizes=None): """ Update ``vals`` with image fields resized as expected. """ + if not sizes: + sizes = {} + url = None if big_name in vals and is_url(vals[big_name]): url = vals[big_name] @@ -20,7 +23,7 @@ def updated_image_resize_images(vals, big_name='image', medium_name='image_mediu vals.update({medium_name: url}) vals.update({small_name: url}) else: - super_image_resize_images(vals, big_name, medium_name, small_name) + super_image_resize_images(vals, big_name, medium_name, small_name, sizes=sizes) def is_url(value): @@ -31,11 +34,11 @@ def is_url(value): super_image_resize_image = tools.image_resize_image -def updated_image_resize_image(base64_source, size=(1024, 1024), encoding='base64', filetype=None, avoid_if_small=False): +def updated_image_resize_image(base64_source, size=(1024, 1024), encoding='base64', filetype=None, avoid_if_small=False, upper_limit=False): source_for_check = base64_source.decode("utf-8") if isinstance(base64_source, bytes) else base64_source if is_url(source_for_check): return source_for_check - return super_image_resize_image(base64_source, size=size, encoding=encoding, filetype=filetype, avoid_if_small=avoid_if_small) + return super_image_resize_image(base64_source, size=size, encoding=encoding, filetype=filetype, avoid_if_small=avoid_if_small, upper_limit=upper_limit) def updated_image_resize_image_big(base64_source, size=(1024, 1024), encoding='base64', filetype=None, avoid_if_small=True): @@ -61,19 +64,24 @@ def updated_image_resize_image_small(base64_source, size=(64, 64), encoding='bas def updated_image_get_resized_images(base64_source, return_big=False, return_medium=True, return_small=True, big_name='image', medium_name='image_medium', small_name='image_small', - avoid_resize_big=True, avoid_resize_medium=False, avoid_resize_small=False): + avoid_resize_big=True, avoid_resize_medium=False, avoid_resize_small=False, sizes=None): """ copy-pasted from odoo/tools/image.py::image_get_resized_images because we rewrite image_resize_image function. """ + if not sizes: + sizes = {} return_dict = dict() + size_big = sizes.get(big_name, (1024, 1024)) + size_medium = sizes.get(medium_name, (128, 128)) + size_small = sizes.get(small_name, (64, 64)) if isinstance(base64_source, tools.pycompat.text_type): base64_source = base64_source.encode('ascii') if return_big: - return_dict[big_name] = updated_image_resize_image_big(base64_source, avoid_if_small=avoid_resize_big) + return_dict[big_name] = updated_image_resize_image_big(base64_source, avoid_if_small=avoid_resize_big, size=size_big) if return_medium: - return_dict[medium_name] = updated_image_resize_image_medium(base64_source, avoid_if_small=avoid_resize_medium) + return_dict[medium_name] = updated_image_resize_image_medium(base64_source, avoid_if_small=avoid_resize_medium, size=size_medium) if return_small: - return_dict[small_name] = updated_image_resize_image_small(base64_source, avoid_if_small=avoid_resize_small) + return_dict[small_name] = updated_image_resize_image_small(base64_source, avoid_if_small=avoid_resize_small, size=size_small) return return_dict diff --git a/ir_attachment_url/models/ir_http.py b/ir_attachment_url/models/ir_http.py index 77f756dcf8..87bd800f83 100644 --- a/ir_attachment_url/models/ir_http.py +++ b/ir_attachment_url/models/ir_http.py @@ -19,13 +19,11 @@ class IrHttp(models.AbstractModel): def binary_content(cls, 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', - access_token=None, env=None): + access_token=None, related_id=None, access_mode=None, env=None): """ Get file, attachment or downloadable content - If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the binary field (via ``default_get``), otherwise fetches the field for that precise record. - :param str xmlid: xmlid of the record :param str model: name of the model to fetch the binary from :param int id: id of the record from which to fetch the binary @@ -35,6 +33,8 @@ def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas :param str filename_field: if not create an filename with model-id-field :param bool download: apply headers to download the file :param str mimetype: mintype of the field (for headers) + :param related_id: the id of another record used for custom_check + :param access_mode: if truthy, will call custom_check to fetch the object that contains the binary. :param str default_mimetype: default mintype if no mintype found :param str access_token: optional token for unauthenticated access only available for ir.attachment @@ -45,21 +45,25 @@ def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas # get object and content obj = None if xmlid: - obj = env.ref(xmlid, False) - elif id and model == 'ir.attachment' and access_token: - obj = env[model].sudo().browse(int(id)) - if not consteq(obj.access_token, access_token): - return (403, [], None) + obj = cls._xmlid_to_obj(env, xmlid) elif id and model in env.registry: obj = env[model].browse(int(id)) - # obj exists if not obj or not obj.exists() or field not in obj: return (404, [], None) + # access token grant access + if model == 'ir.attachment' and access_token: + obj = obj.sudo() + if access_mode: + if not cls._check_access_mode(env, id, access_mode, model, access_token=access_token, related_id=related_id): + return (403, [], None) + elif not consteq(obj.access_token or u'', access_token): + return (403, [], None) + # check read access try: - last_update = obj['__last_update'] + obj['__last_update'] except AccessError: return (403, [], None) @@ -79,7 +83,8 @@ def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas if module_resource_path.startswith(module_path): with open(module_resource_path, 'rb') as f: content = base64.b64encode(f.read()) - last_update = pycompat.text_type(os.path.getmtime(module_resource_path)) + # lint error fix (unused variable) + # last_update = pycompat.text_type(os.path.getmtime(module_resource_path)) if not module_resource_path: module_resource_path = obj.url @@ -130,7 +135,7 @@ def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas # cache etag = bool(request) and request.httprequest.headers.get('If-None-Match') - retag = '"%s"' % hashlib.md5(last_update.encode('utf-8')).hexdigest() + retag = '"%s"' % hashlib.md5(pycompat.to_text(content).encode('utf-8')).hexdigest() status = status or (304 if etag == retag else 200) headers.append(('ETag', retag)) headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0))) diff --git a/ir_attachment_url/tests/test_data_get.py b/ir_attachment_url/tests/test_data_get.py index 93a561fd4c..6210dbe764 100644 --- a/ir_attachment_url/tests/test_data_get.py +++ b/ir_attachment_url/tests/test_data_get.py @@ -1,13 +1,12 @@ import logging -from openerp.tests.common import HttpCase +from odoo.tests.common import HttpCase, tagged _logger = logging.getLogger(__name__) +@tagged('post_install', '-at_install') class TestDataGet(HttpCase): - at_install = False - post_install = True def test_data_get(self): test_attachment = self.env.ref('ir_attachment_url.test_url_attachment')