[IMP] base, website: small refactoring
Mainly to simplify website overrides and general api closes odoo/odoo#121376 Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
This commit is contained in:
@@ -64,9 +64,7 @@ class WebsocketController(Controller):
|
||||
prevent new worker versions to be loaded from the browser cache.
|
||||
"""
|
||||
bundle = 'bus.websocket_worker_assets'
|
||||
assets_params = request.env["ir.asset"]._get_assets_params()
|
||||
files, _ = request.env["ir.qweb"]._get_asset_content(bundle, assets_params=assets_params)
|
||||
asset = AssetsBundle(bundle, files, assets_params=assets_params)
|
||||
asset = request.env["ir.qweb"]._get_asset_bundle(bundle)
|
||||
stream = request.env['ir.binary']._get_stream_from(asset.js(
|
||||
is_minified="assets" not in request.session.debug
|
||||
))
|
||||
|
||||
@@ -20,8 +20,7 @@ class LivechatController(http.Controller):
|
||||
DOM of the livechat to avoid conflicts.
|
||||
"""
|
||||
bundle = 'im_livechat.assets_embed'
|
||||
files, _ = request.env["ir.qweb"]._get_asset_content(bundle)
|
||||
asset = AssetsBundle(bundle, files)
|
||||
asset = request.env["ir.qweb"]._get_asset_bundle(bundle)
|
||||
if ext == 'css':
|
||||
raise request.not_found()
|
||||
stream = request.env['ir.binary']._get_stream_from(asset.js())
|
||||
@@ -30,8 +29,7 @@ class LivechatController(http.Controller):
|
||||
@http.route('/im_livechat/assets_embed.<any(css, js):ext>', type='http', auth='public', cors='*')
|
||||
def assets_embed(self, ext, **kwargs):
|
||||
bundle = 'im_livechat.assets_embed'
|
||||
files, _ = request.env["ir.qweb"]._get_asset_content(bundle)
|
||||
asset = AssetsBundle(bundle, files)
|
||||
asset = request.env["ir.qweb"]._get_asset_bundle(bundle)
|
||||
if ext not in ('css', 'js'):
|
||||
raise request.not_found()
|
||||
stream = request.env['ir.binary']._get_stream_from(getattr(asset, ext)())
|
||||
@@ -44,8 +42,7 @@ class LivechatController(http.Controller):
|
||||
@http.route('/im_livechat/emoji_bundle', type='http', auth='public', cors='*')
|
||||
def get_emoji_bundle(self):
|
||||
bundle = 'mail.assets_emoji'
|
||||
files, _ = request.env["ir.qweb"]._get_asset_content(bundle)
|
||||
asset = AssetsBundle(bundle, files)
|
||||
asset = request.env["ir.qweb"]._get_asset_bundle(bundle)
|
||||
stream = request.env['ir.binary']._get_stream_from(asset.js())
|
||||
return stream.get_response()
|
||||
|
||||
|
||||
@@ -36,8 +36,7 @@ class TestQweb(TransactionCaseWithUserDemo):
|
||||
html = demo_env['ir.qweb']._render('test_website.test_template', {"user": demo}, website_id=website.id)
|
||||
asset_bundle_xmlid = 'test_website.test_bundle'
|
||||
qweb = self.env['ir.qweb']
|
||||
files, _ = qweb._get_asset_content(asset_bundle_xmlid)
|
||||
bundle = qweb._get_asset_bundle(asset_bundle_xmlid, files, env=self.env, css=True, js=True)
|
||||
bundle = qweb._get_asset_bundle(asset_bundle_xmlid, css=True, js=True)
|
||||
|
||||
asset_version_js = bundle.get_version('js')
|
||||
asset_version_css = bundle.get_version('css')
|
||||
|
||||
@@ -607,9 +607,7 @@ class Web_Editor(http.Controller):
|
||||
if re.match('^o-color-([1-5])$', css_color_value):
|
||||
if not bundle_css:
|
||||
bundle = 'web.assets_frontend'
|
||||
files, _ = request.env["ir.qweb"]._get_asset_content(bundle)
|
||||
assets_params = request.env["ir.asset"]._get_assets_params()
|
||||
asset = AssetsBundle(bundle, files, assets_params=assets_params)
|
||||
asset = request.env["ir.qweb"]._get_asset_bundle(bundle)
|
||||
bundle_css = asset.css().index_content
|
||||
color_search = re.search(r'(?i)--%s:\s+(%s|%s)' % (css_color_value, regex_hex, regex_rgba), bundle_css)
|
||||
if not color_search:
|
||||
|
||||
@@ -10,11 +10,18 @@ class IrAsset(models.Model):
|
||||
key = fields.Char(copy=False) # used to resolve multiple assets in a multi-website environment
|
||||
website_id = fields.Many2one('website', ondelete='cascade')
|
||||
|
||||
def _get_assets_params(self):
|
||||
params = super()._get_assets_params()
|
||||
def _get_asset_params(self):
|
||||
params = super()._get_asset_params()
|
||||
params['website_id'] = self.env['website'].get_current_website(fallback=False).id
|
||||
return params
|
||||
|
||||
def _get_asset_extra(self, extra, website_id=None, **params):
|
||||
extra = super()._get_asset_extra(extra, **params)
|
||||
if extra == '%':
|
||||
return extra
|
||||
website_id_path = website_id and ('%s/' % website_id) or ''
|
||||
return website_id_path + extra
|
||||
|
||||
def _get_related_assets(self, domain, website_id=None, **params):
|
||||
if website_id:
|
||||
domain += self.env['website'].website_domain(website_id)
|
||||
|
||||
@@ -18,22 +18,6 @@ _logger = logging.getLogger(__name__)
|
||||
re_background_image = re.compile(r"(background-image\s*:\s*url\(\s*['\"]?\s*)([^)'\"]+)")
|
||||
|
||||
|
||||
class AssetsBundleMultiWebsite(AssetsBundle):
|
||||
def _get_asset_url_values(self, id, unique, extra, name, sep, extension):
|
||||
if extra != '%':
|
||||
website_id = self.assets_params.get('website_id')
|
||||
website_id_path = website_id and ('%s/' % website_id) or ''
|
||||
extra = website_id_path + extra
|
||||
res = super(AssetsBundleMultiWebsite, self)._get_asset_url_values(id, unique, extra, name, sep, extension)
|
||||
return res
|
||||
|
||||
def get_debug_asset_url(self, extra='', name='%', extension='%'):
|
||||
if extra != '%':
|
||||
website_id = self.assets_params.get('website_id')
|
||||
website_id_path = website_id and ('%s/' % website_id) or ''
|
||||
extra = website_id_path + extra
|
||||
return super(AssetsBundleMultiWebsite, self).get_debug_asset_url(extra, name, extension)
|
||||
|
||||
class IrQWeb(models.AbstractModel):
|
||||
""" IrQWeb object for rendering stuff in the website context """
|
||||
|
||||
@@ -108,9 +92,6 @@ class IrQWeb(models.AbstractModel):
|
||||
|
||||
return irQweb
|
||||
|
||||
def _get_asset_bundle(self, xmlid, files=None, env=None, css=True, js=True, debug_assets=False, rtl=False, assets_params=None):
|
||||
return AssetsBundleMultiWebsite(xmlid, files, env=env, css=css, js=js, debug_assets=debug_assets, rtl=rtl, assets_params=assets_params)
|
||||
|
||||
def _post_processing_att(self, tagName, atts):
|
||||
if atts.get('data-no-post-process'):
|
||||
return atts
|
||||
|
||||
@@ -243,15 +243,13 @@ class TestUi(odoo.tests.HttpCase):
|
||||
'website_id': new_website.id,
|
||||
})
|
||||
|
||||
files, _ = self.env['ir.qweb']._get_asset_content(asset_bundle_xmlid, assets_params={'website_id': website_default.id})
|
||||
self.assertNotIn(custom_url, [f['url'] for f in files])
|
||||
base_website_bundle = self.env['ir.qweb']._get_asset_bundle(asset_bundle_xmlid, files, env=self.env, assets_params={'website_id': website_default.id})
|
||||
base_website_bundle = self.env['ir.qweb']._get_asset_bundle(asset_bundle_xmlid, assets_params={'website_id': website_default.id})
|
||||
self.assertNotIn(custom_url, [f['url'] for f in base_website_bundle.files])
|
||||
base_website_css_version = base_website_bundle.get_version('css')
|
||||
base_website_js_version = base_website_bundle.get_version('js')
|
||||
|
||||
files, _ = self.env['ir.qweb']._get_asset_content('website.assets_wysiwyg', assets_params={'website_id': new_website.id})
|
||||
self.assertIn(custom_url, [f['url'] for f in files])
|
||||
new_website_bundle_modified = self.env['ir.qweb']._get_asset_bundle(asset_bundle_xmlid, files, env=self.env, assets_params={'website_id': new_website.id})
|
||||
new_website_bundle_modified = self.env['ir.qweb']._get_asset_bundle('website.assets_wysiwyg', assets_params={'website_id': new_website.id})
|
||||
self.assertIn(custom_url, [f['url'] for f in new_website_bundle_modified.files])
|
||||
self.assertEqual(new_website_bundle_modified.get_version('css'), base_website_css_version)
|
||||
self.assertNotEqual(new_website_bundle_modified.get_version('js'), base_website_js_version, "js version for new website should now have been changed")
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ from odoo.modules.module import get_resource_path
|
||||
from odoo.tools import (func, misc, transpile_javascript,
|
||||
is_odoo_module, SourceMapGenerator, profiler,
|
||||
apply_inheritance_specs)
|
||||
from odoo.tools.constants import SCRIPT_EXTENSIONS, STYLE_EXTENSIONS
|
||||
from odoo.tools.misc import file_open, html_escape as escape
|
||||
from odoo.tools.pycompat import to_text
|
||||
|
||||
@@ -39,7 +40,6 @@ _logger = logging.getLogger(__name__)
|
||||
|
||||
EXTENSIONS = (".js", ".css", ".scss", ".sass", ".less", ".xml")
|
||||
|
||||
|
||||
class CompileError(RuntimeError): pass
|
||||
|
||||
class AssetError(Exception):
|
||||
@@ -57,7 +57,7 @@ class AssetsBundle(object):
|
||||
|
||||
TRACKED_BUNDLES = ['web.assets_common', 'web.assets_backend']
|
||||
|
||||
def __init__(self, name, files, env=None, css=True, js=True, debug_assets=False, rtl=False, assets_params=None):
|
||||
def __init__(self, name, files, external_assets=(), env=None, css=True, js=True, debug_assets=False, rtl=False, assets_params=None):
|
||||
"""
|
||||
:param name: bundle name
|
||||
:param files: files to be added to the bundle
|
||||
@@ -77,6 +77,11 @@ class AssetsBundle(object):
|
||||
self.has_js = js
|
||||
self._checksum_cache = {}
|
||||
self.is_debug_assets = debug_assets
|
||||
self.external_assets = [
|
||||
node
|
||||
for node in external_assets
|
||||
if (css and node[0].rpartition('.')[2] in STYLE_EXTENSIONS) or (js and node[0].rpartition('.')[2] in SCRIPT_EXTENSIONS)
|
||||
]
|
||||
|
||||
# asset-wide html "media" attribute
|
||||
for f in files:
|
||||
@@ -139,7 +144,7 @@ class AssetsBundle(object):
|
||||
src = self.get_debug_asset_url(name=js_attachment.name, extension='') if self.is_debug_assets else js_attachment[0].url
|
||||
response.append((src, None))
|
||||
|
||||
return response
|
||||
return self.external_assets + response
|
||||
|
||||
def get_version(self, asset_type):
|
||||
return self.get_checksum(asset_type)[0:7]
|
||||
@@ -162,26 +167,12 @@ class AssetsBundle(object):
|
||||
self._checksum_cache[asset_type] = hashlib.sha512(unique_descriptor.encode()).hexdigest()[:64]
|
||||
return self._checksum_cache[asset_type]
|
||||
|
||||
def _get_asset_template_url(self):
|
||||
return "/web/assets/{id}-{unique}/{extra}{name}{sep}{extension}"
|
||||
|
||||
def _get_asset_url_values(self, id, unique, extra, name, sep, extension): # extra can contain direction or/and website
|
||||
return {
|
||||
'id': id,
|
||||
'unique': unique,
|
||||
'extra': extra,
|
||||
'name': name,
|
||||
'sep': sep,
|
||||
'extension': extension,
|
||||
'params': self.assets_params,
|
||||
}
|
||||
|
||||
def get_asset_url(self, id='%', unique='%', extra='', name='%', sep="%", extension='%'):
|
||||
return self._get_asset_template_url().format(
|
||||
**self._get_asset_url_values(id=id, unique=unique, extra=extra, name=name, sep=sep, extension=extension)
|
||||
)
|
||||
def get_asset_url(self, attachment_id='%', unique='%', extra='', name='%', sep=".", extension='%'):
|
||||
extra = self.env['ir.asset']._get_asset_extra(extra, **self.assets_params)
|
||||
return f"/web/assets/{attachment_id}-{unique}/{extra}{name}{sep}{extension}"
|
||||
|
||||
def get_debug_asset_url(self, extra='', name='%', extension='%'):
|
||||
extra = self.env['ir.asset']._get_asset_extra(extra, **self.assets_params)
|
||||
return f"/web/assets/debug/{extra}{name}{extension}"
|
||||
|
||||
def _unlink_attachments(self, attachments):
|
||||
@@ -213,13 +204,12 @@ class AssetsBundle(object):
|
||||
url = self.get_asset_url(
|
||||
extra='%s' % ('rtl/' if is_css and self.rtl else ''),
|
||||
name=self.name,
|
||||
sep='.',
|
||||
extension=extension,
|
||||
)
|
||||
|
||||
domain = [
|
||||
('url', '=like', url),
|
||||
'!', ('url', '=like', self.get_asset_url(unique=self.get_version('css' if is_css else 'js')))
|
||||
'!', ('url', '=like', self.get_asset_url(unique=self.get_version('css' if is_css else 'js'), sep='%'))
|
||||
]
|
||||
attachments = ira.sudo().search(domain)
|
||||
# avoid to invalidate cache if it's already empty (mainly useful for test)
|
||||
@@ -251,7 +241,6 @@ class AssetsBundle(object):
|
||||
unique=unique,
|
||||
extra=extra, # not sure about css.map
|
||||
name=self.name,
|
||||
sep='.',
|
||||
extension=extension,
|
||||
)
|
||||
query = """
|
||||
@@ -273,8 +262,7 @@ class AssetsBundle(object):
|
||||
unique=unique,
|
||||
extra='%', #ignore website_id and rtl
|
||||
name=self.name,
|
||||
sep='.',
|
||||
extension='%s' % extension,
|
||||
extension=extension,
|
||||
)
|
||||
|
||||
self.env.cr.execute(query, [SUPERUSER_ID, fallback_url_pattern])
|
||||
@@ -295,11 +283,10 @@ class AssetsBundle(object):
|
||||
self.add_post_rollback()
|
||||
attachment = self.env['ir.attachment'].with_user(SUPERUSER_ID).create(values)
|
||||
url = self.get_asset_url(
|
||||
id=attachment.id,
|
||||
attachment_id=attachment.id,
|
||||
unique=unique,
|
||||
extra=extra,
|
||||
name=self.name,
|
||||
sep='.',
|
||||
extension=extension,
|
||||
)
|
||||
attachment.url = url
|
||||
@@ -353,11 +340,10 @@ class AssetsBundle(object):
|
||||
self.add_post_rollback()
|
||||
attachment = ira.with_user(SUPERUSER_ID).create(values)
|
||||
url = self.get_asset_url(
|
||||
id=attachment.id,
|
||||
attachment_id=attachment.id,
|
||||
unique=self.get_version('css' if is_css else 'js'),
|
||||
extra='%s' % ('rtl/' if extension in ['css', 'min.css'] and self.rtl else ''),
|
||||
name=self.name,
|
||||
sep='.',
|
||||
extension=extension,
|
||||
)
|
||||
attachment.url = url
|
||||
|
||||
@@ -90,13 +90,20 @@ class IrAsset(models.Model):
|
||||
active = fields.Boolean(string='active', default=True)
|
||||
sequence = fields.Integer(string="Sequence", default=DEFAULT_SEQUENCE, required=True)
|
||||
|
||||
def _get_assets_params(self):
|
||||
def _get_asset_params(self):
|
||||
"""
|
||||
This method can be overriden to add param _get_asset_paths call.
|
||||
Those params will be part of the orm cache key
|
||||
"""
|
||||
return {}
|
||||
|
||||
def _get_asset_extra(self, extra):
|
||||
"""
|
||||
This method can be overriden to use param as keyword arguments
|
||||
Return the extra based on additionnal assets_params
|
||||
"""
|
||||
return extra
|
||||
|
||||
@tools.conditional(
|
||||
'xml' not in tools.config['dev_mode'],
|
||||
tools.ormcache('bundle', 'tuple(sorted(assets_params.items()))'),
|
||||
@@ -120,7 +127,7 @@ class IrAsset(models.Model):
|
||||
|
||||
:param bundle: name of the bundle from which to fetch the file paths
|
||||
:param assets_params: parameters needed by overrides, mainly website_id
|
||||
see _get_assets_params
|
||||
see _get_asset_params
|
||||
:returns: the list of tuples (path, addon, bundle)
|
||||
"""
|
||||
installed = self._get_installed_addons_list()
|
||||
@@ -242,7 +249,7 @@ class IrAsset(models.Model):
|
||||
"""
|
||||
installed = self._get_installed_addons_list()
|
||||
target_path, _full_path, _modified = self._get_paths(target_path_def, installed)[0]
|
||||
assets_params = self._get_assets_params()
|
||||
assets_params = self._get_asset_params()
|
||||
asset_paths = self._get_asset_paths(root_bundle, assets_params)
|
||||
|
||||
for path, _full_path, bundle, _modified in asset_paths:
|
||||
|
||||
@@ -2426,7 +2426,7 @@ class IrQWeb(models.AbstractModel):
|
||||
Else, the assets will be generated only once and then stored in cache.
|
||||
"""
|
||||
rtl = self.env['res.lang']._lang_get_direction(self.env.context.get('lang') or self.env.user.lang) == 'rtl'
|
||||
assets_params = self.env['ir.asset']._get_assets_params() # website_id
|
||||
assets_params = self.env['ir.asset']._get_asset_params() # website_id
|
||||
debug_assets = debug and 'assets' in debug
|
||||
|
||||
if debug_assets:
|
||||
@@ -2491,7 +2491,7 @@ class IrQWeb(models.AbstractModel):
|
||||
|
||||
def _get_asset_content(self, bundle, assets_params=None):
|
||||
if assets_params is None:
|
||||
assets_params = self.env['ir.asset']._get_assets_params() # website_id
|
||||
assets_params = self.env['ir.asset']._get_asset_params() # website_id
|
||||
asset_paths = self.env['ir.asset']._get_asset_paths(bundle=bundle, assets_params=assets_params)
|
||||
files = []
|
||||
external_asset = []
|
||||
@@ -2507,8 +2507,11 @@ class IrQWeb(models.AbstractModel):
|
||||
external_asset.append((path, None))
|
||||
return (files, external_asset)
|
||||
|
||||
def _get_asset_bundle(self, bundle_name, files=None, env=None, css=True, js=True, debug_assets=False, rtl=False, assets_params=None):
|
||||
return AssetsBundle(bundle_name, files, env=env, css=css, js=js, debug_assets=debug_assets, rtl=rtl, assets_params=assets_params)
|
||||
def _get_asset_bundle(self, bundle_name, css=True, js=True, debug_assets=False, rtl=False, assets_params=None):
|
||||
if assets_params is None:
|
||||
assets_params = self.env['ir.asset']._get_asset_params()
|
||||
files, external_assets = self._get_asset_content(bundle_name, assets_params)
|
||||
return AssetsBundle(bundle_name, files, external_assets, env=self.env, css=css, js=js, debug_assets=debug_assets, rtl=rtl, assets_params=assets_params)
|
||||
|
||||
def _links_to_nodes(self, paths, defer_load=False, lazy_load=False, media=None):
|
||||
return [self._link_to_node(path, defer_load=defer_load, lazy_load=lazy_load, media=media) for path in paths]
|
||||
@@ -2564,11 +2567,8 @@ class IrQWeb(models.AbstractModel):
|
||||
return ('script', attributes, None)
|
||||
|
||||
def _generate_asset_links(self, bundle, css=True, js=True, debug_assets=False, assets_params=None, rtl=False):
|
||||
aggregable_files, external_assets = self._get_asset_content(bundle, assets_params=assets_params)
|
||||
external_assets = [node for node in external_assets if (css and node[0].rpartition('.')[2] in STYLE_EXTENSIONS) or (js and node[0].rpartition('.')[2] in SCRIPT_EXTENSIONS)]
|
||||
asset_bundle = self._get_asset_bundle(bundle, aggregable_files, env=self.env, css=css, js=js, debug_assets=debug_assets, rtl=rtl, assets_params=assets_params)
|
||||
bundle_links = asset_bundle.get_links()
|
||||
return external_assets + bundle_links
|
||||
asset_bundle = self._get_asset_bundle(bundle, css=css, js=js, debug_assets=debug_assets, rtl=rtl, assets_params=assets_params)
|
||||
return asset_bundle.get_links()
|
||||
|
||||
def _get_asset_link_urls(self, bundle, debug=False):
|
||||
asset_nodes = self._get_asset_nodes(bundle, js=False, debug=debug)
|
||||
|
||||
@@ -742,8 +742,7 @@ class TestAssetsBundleWithIRAMock(FileTouchable):
|
||||
|
||||
def _get_asset(self):
|
||||
with patch.object(type(self.env['ir.asset']), '_get_installed_addons_list', Mock(return_value=self.installed_modules)):
|
||||
files, _ = self.env['ir.qweb']._get_asset_content(self.stylebundle_name)
|
||||
return AssetsBundle(self.stylebundle_name, files, env=self.env, debug_assets=True)
|
||||
return self.env['ir.qweb']._get_asset_bundle(self.stylebundle_name, debug_assets=True)
|
||||
|
||||
def _bundle(self, asset, should_create, should_unlink, reason=''):
|
||||
self.counter.clear()
|
||||
|
||||
Reference in New Issue
Block a user