From c0ab464dc7482e8198ac789cc76aa9ed45e8e2a0 Mon Sep 17 00:00:00 2001 From: Lucas Perais Date: Fri, 19 Jan 2024 13:16:20 +0000 Subject: [PATCH] [FIX] base, web (qweb): image field in raw data mode handles options Commit[1] implemented a way to output an image as its raw representation `` It is useful for integrating an image of a record not accessible publicly. However the original commit forgot to allow the img node to handle the options passed to the field. Classes in particular were absent After this commit, the options are handled correctly, and the image in raw mode has the right classes. opw-3517861 [1]: f8b901d04b6c5874b56576f9b89899b2812296f2 closes odoo/odoo#151410 X-original-commit: dbb22351921629aad845e29ebfa8b4083b4e745a Signed-off-by: Lucas Perais (lpe) --- addons/web/models/ir_qweb_fields.py | 10 +++++--- addons/web/tests/__init__.py | 1 + addons/web/tests/test_ir_qweb.py | 30 +++++++++++++++++++++++ odoo/addons/base/models/ir_qweb_fields.py | 8 ++++-- 4 files changed, 44 insertions(+), 5 deletions(-) create mode 100644 addons/web/tests/test_ir_qweb.py diff --git a/addons/web/models/ir_qweb_fields.py b/addons/web/models/ir_qweb_fields.py index 2bf7f7164b3..e4cc0f94132 100644 --- a/addons/web/models/ir_qweb_fields.py +++ b/addons/web/models/ir_qweb_fields.py @@ -64,15 +64,19 @@ class Image(models.AbstractModel): "That is because the image goes into the tag, or it gets the " \ "hose again." + src = src_zoom = None if options.get('qweb_img_raw_data', False): - return super(Image, self).record_to_html(record, field_name, options) + value = record[field_name] + if value is False: + return False + src = self._get_src_data_b64(value, options) + else: + src, src_zoom = self._get_src_urls(record, field_name, options) aclasses = ['img', 'img-fluid'] if options.get('qweb_img_responsive', True) else ['img'] aclasses += options.get('class', '').split() classes = ' '.join(map(escape, aclasses)) - src, src_zoom = self._get_src_urls(record, field_name, options) - if options.get('alt-field') and options['alt-field'] in record and record[options['alt-field']]: alt = escape(record[options['alt-field']]) elif options.get('alt'): diff --git a/addons/web/tests/__init__.py b/addons/web/tests/__init__.py index a4a3dac207f..00232ed8159 100644 --- a/addons/web/tests/__init__.py +++ b/addons/web/tests/__init__.py @@ -22,3 +22,4 @@ from . import test_translate from . import test_web_redirect from . import test_res_users from . import test_webmanifest +from . import test_ir_qweb diff --git a/addons/web/tests/test_ir_qweb.py b/addons/web/tests/test_ir_qweb.py new file mode 100644 index 00000000000..06d3bd3e724 --- /dev/null +++ b/addons/web/tests/test_ir_qweb.py @@ -0,0 +1,30 @@ +from lxml import etree +from odoo.tests.common import TransactionCase + +class TestIrQweb(TransactionCase): + def test_image_field(self): + view = self.env["ir.ui.view"].create({ + "key": "web.test_qweb", + "type": "qweb", + "arch": """ + + """ + }) + partner = self.env["res.partner"].create({ + "name": "test image partner", + "image_128": "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAF0lEQVR4nGJxKFrEwMDAxAAGgAAAAP//D+IBWx9K7TUAAAAASUVORK5CYII=", + }) + + html = view._render_template(view.id, {"is_raw_image": True, "record": partner}) + tree = etree.fromstring(html) + img = tree.find("img") + self.assertTrue(img.get("src").startswith("data:image/png;base64")) + self.assertEqual(img.get("class"), "img img-fluid") + self.assertEqual(img.get("alt"), "test image partner") + + html = view._render_template(view.id, {"is_raw_image": False, "record": partner}) + tree = etree.fromstring(html) + img = tree.find("img") + self.assertTrue(img.get("src").startswith("/web/image")) + self.assertEqual(img.get("class"), "img img-fluid") + self.assertEqual(img.get("alt"), "test image partner") diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py index f3844173ab2..431a95d607a 100644 --- a/odoo/addons/base/models/ir_qweb_fields.py +++ b/odoo/addons/base/models/ir_qweb_fields.py @@ -389,7 +389,7 @@ class ImageConverter(models.AbstractModel): _inherit = 'ir.qweb.field' @api.model - def value_to_html(self, value, options): + def _get_src_data_b64(self, value, options): try: # FIXME: maaaaaybe it could also take raw bytes? image = Image.open(BytesIO(base64.b64decode(value))) image.verify() @@ -398,7 +398,11 @@ class ImageConverter(models.AbstractModel): except: # image.verify() throws "suitable exceptions", I have no idea what they are raise ValueError("Invalid image content") - return Markup('' % (Image.MIME[image.format], value.decode('ascii'))) + return "data:%s;base64,%s" % (Image.MIME[image.format], value.decode('ascii')) + + @api.model + def value_to_html(self, value, options): + return Markup('') % self._get_src_data_b64(value, options) class ImageUrlConverter(models.AbstractModel): """ ``image_url`` widget rendering, inserts an image tag in the