[FIX] base, website: don't cleanup invalid bundle

Before this commit the clean_assetbundle could unlink invalid
attachment, mostly when generating a no website assetbundle with
a different version than a website one, the website assetbundle will be
deleted.

Generating a new asset bundle attachment /web/assets/439-b4c80c3/1/web.assets_frontend.min.css (id:439)
Generating a new asset bundle attachment /web/assets/440-3723971/web.assets_frontend.min.css (id:440)
Deleting attachments [439] (matching /web/assets/%-%/web.assets_frontend.min.css) because it was replaced with /web/assets/%-3723971/%%%

The issue is that %-%/ will match 439-b4c80c3/1/ and not only
439-b4c80c3/

Note that it looks like this issue existed for a while but was invisible
because before 16.4 clean_attachment was invalidating the ormcache,
hiding the fact that a still valid asset was deleted and regenerated.

The proposed fix replaces the domain with %-_______/. The unique is
always 7 character long. Note that this change was already made in 17.0
when removing the id from the asset url so this doesn't need to be
completely forward-ported.

opw-3558552

closes odoo/odoo#145452

X-original-commit: 2ac466547e01bfd65415a53ae1efc9d45d9299fb
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
This commit is contained in:
Xavier-Do
2023-12-13 14:15:40 +00:00
parent 448f36ec4d
commit 30db58e5e6
3 changed files with 40 additions and 3 deletions
+36
View File
@@ -100,6 +100,42 @@ class TestWebsiteAssets(odoo.tests.HttpCase):
new_public_assets_links = re.findall(r'(/web/assets/\d+/\w{7}/web.assets_frontend\..+)"/>', page)
self.assertEqual(new_admin_assets_links, new_public_assets_links, "t-cache should have been invalidated for public user too")
def test_invalid_unlink(self):
self.env['ir.attachment'].search([('url', '=like', '/web/assets/%')]).unlink()
asset_bundle_xmlid = 'web.assets_frontend'
website_default = self.env['website'].search([], limit=1)
code = b"document.body.dataset.hello = 'world';"
attach = self.env['ir.attachment'].create({
'name': 'EditorExtension.css',
'mimetype': 'text/css',
'raw': code,
})
custom_url = '/_custom/web/content/%s/%s' % (attach.id, attach.name)
attach.url = custom_url
self.env['ir.asset'].create({
'name': 'EditorExtension',
'bundle': asset_bundle_xmlid,
'path': custom_url,
'website_id': website_default.id,
})
website_bundle = self.env['ir.qweb']._get_asset_bundle(asset_bundle_xmlid, assets_params={'website_id': website_default.id})
self.assertIn(custom_url, [f['url'] for f in website_bundle.files])
base_website_css_version = website_bundle.get_version('css')
no_website_bundle = self.env['ir.qweb']._get_asset_bundle(asset_bundle_xmlid)
self.assertNotIn(custom_url, [f['url'] for f in no_website_bundle.files])
self.assertNotEqual(no_website_bundle.get_version('css'), base_website_css_version)
website_attach = website_bundle.css()
self.assertTrue(website_attach.exists())
no_website_bundle.css()
self.assertTrue(website_attach.exists(), 'attachment for website should still exist after generating attachment for no website')
@odoo.tests.tagged('-at_install', 'post_install')
class TestWebAssets(odoo.tests.HttpCase):
def test_assets_url_validation(self):
+2 -1
View File
@@ -150,7 +150,7 @@ class AssetsBundle(object):
self._checksum_cache[asset_type] = hashlib.sha512(unique_descriptor.encode()).hexdigest()[:64]
return self._checksum_cache[asset_type]
def get_asset_url(self, unique='%', extension='%', ignore_params=False):
def get_asset_url(self, unique=ANY_UNIQUE, extension='%', ignore_params=False):
direction = '.rtl' if self.is_css(extension) and self.rtl else ''
bundle_name = f"{self.name}{direction}.{extension}"
return self.env['ir.asset']._get_asset_bundle_url(bundle_name, unique, self.assets_params, ignore_params)
@@ -264,6 +264,7 @@ class AssetsBundle(object):
}
attachment = self.env['ir.attachment'].with_user(SUPERUSER_ID).create(values)
attachment_id = attachment.id
self.clean_attachments(extension)
return self.env['ir.attachment'].sudo().browse(attachment_id)
@@ -15,7 +15,7 @@ import base64
import odoo
from odoo import api, http
from odoo.addons import __path__ as ADDONS_PATH
from odoo.addons.base.models.assetsbundle import AssetsBundle
from odoo.addons.base.models.assetsbundle import AssetsBundle, ANY_UNIQUE
from odoo.addons.base.models.ir_asset import AssetPaths
from odoo.addons.base.models.ir_attachment import IrAttachment
from odoo.modules.module import get_manifest
@@ -147,7 +147,7 @@ class TestJavascriptAssetsBundle(FileTouchable):
bundle = self.jsbundle_name if extension in ['js', 'min.js'] else self.cssbundle_name
direction = '.rtl' if rtl else ''
bundle_name = f"{bundle}{direction}.{extension}"
url = self.env['ir.asset']._get_asset_bundle_url(bundle_name, '%', {})
url = self.env['ir.asset']._get_asset_bundle_url(bundle_name, ANY_UNIQUE, {})
domain = [('url', '=like', url)]
return self.env['ir.attachment'].search(domain)