[FIX] web_editor: prevent crash with some options applied on 404 images
Commit [1] introduced some code that relied on a cache we currently have for processed** images. In case of 404, that cache is not filled... and relying on it thus crashes. This commit circles around the issue by taking profit of [2] which now forces `loadImage` to load a placeholder image in case of a 404. This makes sure that in case of a 404 during the initial call to `loadImage`, the rest of the stack works with the loaded placeholder image. **Note: the current cache is not filled at the `loadImage` level, but later when processing the fetched image. This should be changed in the future (a task has been created). See [3] and [4] which are example of unwanted 404 images due to other issues, which allowed to discover this bug to fix here. Steps to reproduce: - Go on the `website.s_picture_default_image` ir.attachment form view - Change the URL value to a relative path that does not exist - Go on a website page and edit - Drop the "Picture" snippet => Crash => After this fix, no crash but you can also edit the image if you were able to click on it, it would use the placeholder image as source. [1]: https://github.com/odoo/odoo/commit/567e5b58d544e4e56c3a68d148e862a516d77c4f [2]: https://github.com/odoo/odoo/commit/0639c5028c69d8e29c8438b741cc4713d875b06d [3]: https://github.com/odoo/odoo/pull/155015 [4]: https://github.com/odoo/design-themes/pull/767 Related to opw-3693055 and others (see [3] and [4]). closes odoo/odoo#155275 X-original-commit: fbc6a697c1adf67ee8a90c49b0150d6ca170e081 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
@@ -233,6 +233,8 @@ export async function applyModifications(img, dataOptions = {}) {
|
||||
// Crop
|
||||
const container = document.createElement('div');
|
||||
const original = await loadImage(originalSrc);
|
||||
// loadImage may have ended up loading a different src (see: LOAD_IMAGE_404)
|
||||
originalSrc = original.getAttribute('src');
|
||||
container.appendChild(original);
|
||||
await activateCropper(original, 0, data);
|
||||
let croppedImg = $(original).cropper('getCroppedCanvas', {width, height});
|
||||
@@ -358,6 +360,7 @@ export function loadImage(src, img = new Image()) {
|
||||
img.src = source;
|
||||
};
|
||||
// The server will return a placeholder image with the following src.
|
||||
// grep: LOAD_IMAGE_404
|
||||
const placeholderHref = "/web/image/__odoo__unknown__src__/";
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -419,6 +422,8 @@ async function _updateImageData(src, key = 'objectURL') {
|
||||
}
|
||||
/**
|
||||
* Returns the size of a cached image.
|
||||
* Warning: this supposes that the image is already in the cache, i.e. that
|
||||
* _updateImageData was called before.
|
||||
*
|
||||
* @param {String} src used as a key on the image cache map.
|
||||
* @returns {Number} size of the image in bytes.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import wTourUtils from '@website/js/tours/tour_utils';
|
||||
|
||||
wTourUtils.registerWebsitePreviewTour('drop_404_ir_attachment_url', {
|
||||
test: true,
|
||||
url: '/',
|
||||
edition: true,
|
||||
}, () => [
|
||||
wTourUtils.dragNDrop({
|
||||
id: 's_404_snippet',
|
||||
name: '404 Snippet',
|
||||
}),
|
||||
{
|
||||
content: 'Click on the snippet image',
|
||||
trigger: 'iframe .s_404_snippet img',
|
||||
}, {
|
||||
content: 'Once the image UI appears, check the image has no size (404)',
|
||||
trigger: 'iframe .s_404_snippet img',
|
||||
extra_trigger: '.snippet-option-ReplaceMedia',
|
||||
run: function () {
|
||||
const imgEl = this.$anchor[0];
|
||||
if (!imgEl.complete
|
||||
|| imgEl.naturalWidth !== 0
|
||||
|| imgEl.naturalHeight !== 0) {
|
||||
console.error('This is supposed to be a 404 image');
|
||||
}
|
||||
},
|
||||
},
|
||||
wTourUtils.changeOption('ImageTools', 'we-select[data-name="shape_img_opt"] we-toggler'),
|
||||
wTourUtils.changeOption('ImageTools', 'we-button[data-set-img-shape]'),
|
||||
{
|
||||
content: 'Once the shape is applied, check the image has now a size (placeholder image)',
|
||||
trigger: 'iframe .s_404_snippet img[src^="data:"]',
|
||||
run: function () {
|
||||
const imgEl = this.$anchor[0];
|
||||
if (!imgEl.complete
|
||||
|| imgEl.naturalWidth === 0
|
||||
|| imgEl.naturalHeight === 0) {
|
||||
console.error('Even though the original image was a 404, the option should have been applied on the placeholder image');
|
||||
}
|
||||
},
|
||||
},
|
||||
]);
|
||||
@@ -515,3 +515,40 @@ class TestUi(odoo.tests.HttpCase):
|
||||
'path': 'website/static/tests/tour_utils/widget_lifecycle_patch_wysiwyg.js',
|
||||
})
|
||||
self.start_tour(self.env['website'].get_client_action_url('/'), 'widget_lifecycle', login='admin')
|
||||
|
||||
def test_drop_404_ir_attachment_url(self):
|
||||
website_snippets = self.env.ref('website.snippets')
|
||||
self.env['ir.ui.view'].create([{
|
||||
'name': '404 Snippet',
|
||||
'type': 'qweb',
|
||||
'key': 'website.s_404_snippet',
|
||||
'arch': """
|
||||
<section class="s_404_snippet">
|
||||
<div class="container">
|
||||
<img class="img-responsive img-thumbnail" src="/web/image/website.404_ir_attachment"/>
|
||||
</div>
|
||||
</section>
|
||||
""",
|
||||
}, {
|
||||
'type': 'qweb',
|
||||
'inherit_id': website_snippets.id,
|
||||
'arch': """
|
||||
<xpath expr="//t[@t-snippet='website.s_parallax']" position="after">
|
||||
<t t-snippet="website.s_404_snippet"
|
||||
t-thumbnail="/website/static/src/img/snippets_thumbs/s_website_form.svg"/>
|
||||
</xpath>
|
||||
""",
|
||||
}])
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'name': '404_ir_attachment',
|
||||
'type': 'url',
|
||||
'url': '/web/static/__some__typo__.png',
|
||||
'mimetype': 'image/png',
|
||||
})
|
||||
self.env['ir.model.data'].create({
|
||||
'name': '404_ir_attachment',
|
||||
'module': 'website',
|
||||
'model': 'ir.attachment',
|
||||
'res_id': attachment.id,
|
||||
})
|
||||
self.start_tour(self.env['website'].get_client_action_url('/'), 'drop_404_ir_attachment_url', login='admin')
|
||||
|
||||
Reference in New Issue
Block a user