Files
odoo_source/addons/website/models/ir_asset.py
T
Xavier-Do bf3b6b0b8b [IMP] base, web, *: change url formating
Previously proposed formating was trying to normalize extra in one part
of the path. This means that no extra needed a placeholder.

The implementation was meant to be more generic and extendible since a
part of the logic has to be in website.

A suggestion was made to make it more restricted but explicite by
keeping the url simple in web/controllers/binary.py but adding a
controller in website to add this extra part.

The base extra direction is now in the extension, as the min part.

Initial urls:
/web/assets/{unique}/[{website_id}/][rtl/]{bundle_name}[.min].{extension}

New urls:
/web/assets/[{website_id}]/{unique}/{bundle_name}[.rtl][.min].{extension}

Managed by two routes:

/web/assets/<string:unique>/<string:filename>
/web/assets/<int:website_id>/<string:unique>/<string:filename>

Where filename is in the format {bundle_name}[.rtl][.min].{extension}

Multiple possibilities where proposed

- /web/assets/website/<int:website_id>/<string:unique>/<string:filename>
More explicit but prefixing by /website was considered

- /website/assets/<int:website_id>/<string:unique>/<string:filename>
This one is a litle painfull to match similar attachement, where
website is ignored.

- /website/<int:website_id>/assets/<string:unique>/<string:filename>
Almost accepted but subjective, and anyway two previous solution breaks
the cdn mecanism and would need a migration

- /web/assets/<int:website_id>/<string:unique>/<string:filename>
Almost accepted but subjective, and anyway two previous solution breaks
the cdn mecanism and would need a migration

This last solution was not ideal to match without unique
/web/assets/%/<string:filename> can match both

/web/assets/123456/<string:filename>
and
/web/assets/1/123456/<string:filename>

Anyway, matching without unique shouldn't be supported for al (even if
it is kind of supported with any right now) but it will work by changing
unique wildcard to a more specific one (_ * 7)

closes odoo/odoo#131353

Related: odoo/enterprise#47313
Related: odoo/design-themes#730
Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
2023-10-27 11:34:52 +00:00

106 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class IrAsset(models.Model):
_inherit = 'ir.asset'
key = fields.Char(copy=False) # used to resolve multiple assets in a multi-website environment
website_id = fields.Many2one('website', ondelete='cascade')
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_bundle_url(self, filename, unique, assets_params, ignore_params=False):
route_prefix = '/web/assets'
if ignore_params: # we dont care about website id, match both
route_prefix = '/web/assets%'
elif website_id := assets_params.get('website_id', None):
route_prefix = f'/web/assets/{website_id}'
return f'{route_prefix}/{unique}/{filename}'
def _get_related_assets(self, domain, website_id=None, **params):
if website_id:
domain += self.env['website'].website_domain(website_id)
assets = super()._get_related_assets(domain, **params)
return assets.filter_duplicate(website_id)
def _get_active_addons_list(self, website_id=None, **params):
"""Overridden to discard inactive themes."""
addons_list = super()._get_active_addons_list(**params)
if not website_id:
return addons_list
IrModule = self.env['ir.module.module'].sudo()
# discard all theme modules except website.theme_id
themes = IrModule.search(IrModule.get_themes_domain()) - self.env["website"].browse(website_id).theme_id
to_remove = set(themes.mapped('name'))
return [name for name in addons_list if name not in to_remove]
def filter_duplicate(self, website_id=None):
""" Filter current recordset only keeping the most suitable asset per distinct name.
Every non-accessible asset will be removed from the set:
* In non website context, every asset with a website will be removed
* In a website context, every asset from another website
"""
if website_id is not None:
current_website = self.env['website'].browse(website_id)
else:
current_website = self.env['website'].get_current_website(fallback=False)
if not current_website:
return self.filtered(lambda asset: not asset.website_id)
most_specific_assets = self.env['ir.asset']
for asset in self:
if asset.website_id == current_website:
# specific asset: add it if it's for the current website and ignore
# it if it's for another website
most_specific_assets += asset
elif not asset.website_id:
# no key: added either way
if not asset.key:
most_specific_assets += asset
# generic asset: add it iff for the current website, there is no
# specific asset for this asset (based on the same `key` attribute)
elif not any(asset.key == asset2.key and asset2.website_id == current_website for asset2 in self):
most_specific_assets += asset
return most_specific_assets
def write(self, vals):
"""COW for ir.asset. This way editing websites does not impact other
websites. Also this way newly created websites will only
contain the default assets.
"""
current_website_id = self.env.context.get('website_id')
if not current_website_id or self.env.context.get('no_cow'):
return super().write(vals)
for asset in self.with_context(active_test=False):
# No need of COW if the asset is already specific
if asset.website_id:
super(IrAsset, asset).write(vals)
continue
# If already a specific asset for this generic asset, write on it
website_specific_asset = asset.search([
('key', '=', asset.key),
('website_id', '=', current_website_id)
], limit=1)
if website_specific_asset:
super(IrAsset, website_specific_asset).write(vals)
continue
copy_vals = {'website_id': current_website_id, 'key': asset.key}
website_specific_asset = asset.copy(copy_vals)
super(IrAsset, website_specific_asset).write(vals)
return True