196 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Python
		
	
	
# Copyright 2015 Antiun Ingenieria S.L. - Antonio Espinosa
 | 
						|
# Copyright 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
 | 
						|
# Copyright 2018 Ivan Yelizariev <https://it-projects.info/team/yelizariev>
 | 
						|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
 | 
						|
 | 
						|
import logging
 | 
						|
 | 
						|
from odoo import api, fields, models
 | 
						|
 | 
						|
_logger = logging.getLogger(__name__)
 | 
						|
 | 
						|
 | 
						|
class WebsiteTheme(models.Model):
 | 
						|
    _name = 'website.theme'
 | 
						|
    _order = "name"
 | 
						|
    _sql_constraints = [
 | 
						|
        ("name_uniq", "UNIQUE(name)", "Name must be unique"),
 | 
						|
    ]
 | 
						|
 | 
						|
    name = fields.Char(
 | 
						|
        required=True,
 | 
						|
        translate=True,
 | 
						|
    )
 | 
						|
    converted_theme_addon = fields.Char(
 | 
						|
        help="Name of the theme addon that is being converted from single to "
 | 
						|
             "multi website mode.",
 | 
						|
    )
 | 
						|
    dependency_ids = fields.Many2many(
 | 
						|
        "website.theme",
 | 
						|
        "website_theme_dependency_rel",
 | 
						|
        "theme1", "theme2",
 | 
						|
        string="Sub-themes",
 | 
						|
        help="If theme is splitted in different theme-modules, "
 | 
						|
        "they should be in this list. \"Default theme\" should be here too "
 | 
						|
        "in order to make some features (e.g. footer) "
 | 
						|
        "work on each website independently",
 | 
						|
    )
 | 
						|
    asset_ids = fields.One2many(
 | 
						|
        comodel_name="website.theme.asset",
 | 
						|
        inverse_name="theme_id",
 | 
						|
        string="Assets",
 | 
						|
        help="Asset views that will be disabled by default and enabled only "
 | 
						|
             "in websites that enable this theme in multiwebsite mode.",
 | 
						|
    )
 | 
						|
    has_assets = fields.Boolean(compute='_compute_has_assets', store=True)
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    @api.depends('dependency_ids', 'asset_ids')
 | 
						|
    def _compute_has_assets(self):
 | 
						|
        for r in self:
 | 
						|
            r.has_assets = bool(r.get_assets())
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def upstream_dependencies(self):
 | 
						|
        """Returns the theme and all its dependencies"""
 | 
						|
        themes = self
 | 
						|
        while True:
 | 
						|
            new_deps = themes.mapped('dependency_ids') - themes
 | 
						|
            if new_deps:
 | 
						|
                themes |= new_deps
 | 
						|
            else:
 | 
						|
                break
 | 
						|
        return themes
 | 
						|
 | 
						|
    @api.multi
 | 
						|
    def get_assets(self):
 | 
						|
        """Assets of the theme and all its dependencies"""
 | 
						|
        return self.upstream_dependencies().mapped('asset_ids')
 | 
						|
 | 
						|
    def _convert_assets(self):
 | 
						|
        """Generate assets for converted themes"""
 | 
						|
        Asset = self.env["website.theme.asset"]
 | 
						|
 | 
						|
        common_refs = self.env["ir.model.data"]
 | 
						|
 | 
						|
        # add views with customize_show menu, so we can activate them per
 | 
						|
        # website independently
 | 
						|
        common_refs |= self.env['ir.ui.view']\
 | 
						|
                           .with_context(active_test=False)\
 | 
						|
                           .search([
 | 
						|
                               ('website_id', '=', False),
 | 
						|
                               ('customize_show', '=', True),
 | 
						|
                           ]).mapped('model_data_id')
 | 
						|
        _logger.debug('common_refs: %s', common_refs.mapped('complete_name'))
 | 
						|
 | 
						|
        for one in self:
 | 
						|
            refs = self.env["ir.model.data"]
 | 
						|
 | 
						|
            if one.converted_theme_addon:
 | 
						|
                # Get all views owned by the converted theme addon
 | 
						|
                refs |= self.env["ir.model.data"].search([
 | 
						|
                    ("module", "=", one.converted_theme_addon),
 | 
						|
                    ("model", "=", "ir.ui.view"),
 | 
						|
                ])
 | 
						|
 | 
						|
            if refs or one.asset_ids:
 | 
						|
                # add common_refs only for installed themes
 | 
						|
                refs |= common_refs
 | 
						|
 | 
						|
            views = self.env["ir.ui.view"].with_context(active_test=False) \
 | 
						|
                .search([
 | 
						|
                    ("id", "in", refs.mapped("res_id")),
 | 
						|
                    ("type", "=", "qweb"),
 | 
						|
                ])
 | 
						|
            existing = frozenset(
 | 
						|
                one
 | 
						|
                .mapped("asset_ids")
 | 
						|
                .filtered("auto")
 | 
						|
                .mapped("name")
 | 
						|
            )
 | 
						|
            expected = frozenset(views.mapped("xml_id"))
 | 
						|
 | 
						|
            dangling = tuple(existing - expected)
 | 
						|
            # Create a new asset for each theme view
 | 
						|
            for ref in expected - existing:
 | 
						|
                _logger.debug("Creating asset %s for theme %s", ref, one.name)
 | 
						|
                one.asset_ids |= Asset.new({
 | 
						|
                    "name": ref,
 | 
						|
                    "auto": True,
 | 
						|
                })
 | 
						|
            # Delete all dangling assets
 | 
						|
            if dangling:
 | 
						|
                _logger.debug(
 | 
						|
                    "Removing dangling assets for theme %s: %s",
 | 
						|
                    one.name, dangling)
 | 
						|
                Asset.search([("name", "in", dangling)]).unlink()
 | 
						|
        # Turn all assets multiwebsite-only
 | 
						|
        Asset._find_and_deactivate_views()
 | 
						|
 | 
						|
 | 
						|
class WebsiteThemeAsset(models.Model):
 | 
						|
    _name = "website.theme.asset"
 | 
						|
    _order = 'view_priority,view_id,id'
 | 
						|
    _sql_constraints = [
 | 
						|
        ("name_theme_uniq", "UNIQUE(name, theme_id)",
 | 
						|
         "Name must be unique in each theme"),
 | 
						|
    ]
 | 
						|
 | 
						|
    name = fields.Char(
 | 
						|
        name="Reference",
 | 
						|
        required=True,
 | 
						|
        help="External ID of the assets view that inherits from "
 | 
						|
             "`website.assets_frontend` and adds the theme requirements.",
 | 
						|
    )
 | 
						|
    theme_id = fields.Many2one(
 | 
						|
        comodel_name="website.theme",
 | 
						|
        string="Theme",
 | 
						|
        required=True,
 | 
						|
        ondelete="cascade",
 | 
						|
    )
 | 
						|
    view_id = fields.Many2one(
 | 
						|
        comodel_name="ir.ui.view",
 | 
						|
        string="Assets view",
 | 
						|
        help="View that will be enabled when this theme is used in any "
 | 
						|
             "website, and disabled otherwise. Usually used to load assets.",
 | 
						|
    )
 | 
						|
    view_priority = fields.Integer(
 | 
						|
        related='view_id.priority',
 | 
						|
        store=True,
 | 
						|
        readonly=True,
 | 
						|
    )
 | 
						|
    auto = fields.Boolean(
 | 
						|
        string="Auto-generated",
 | 
						|
        help="Created automatically from theme view",
 | 
						|
        default=False,
 | 
						|
    )
 | 
						|
 | 
						|
    @api.model
 | 
						|
    def _find_and_deactivate_views(self):
 | 
						|
        """Find available views and make them multiwebsite-only."""
 | 
						|
        linkable = self.search([
 | 
						|
            "|", ("view_id", "=", False), ("view_id.active", "=", True),
 | 
						|
        ])
 | 
						|
        for one in linkable:
 | 
						|
            try:
 | 
						|
                one.view_id = self.env.ref(one.name)
 | 
						|
                _logger.debug(
 | 
						|
                    "Found view with ref %s: %r",
 | 
						|
                    one.name,
 | 
						|
                    one.view_id,
 | 
						|
                )
 | 
						|
            except ValueError:
 | 
						|
                one.view_id = False
 | 
						|
                _logger.debug("Ref not found: %s", one.name)
 | 
						|
            else:
 | 
						|
                if one.view_id.active:
 | 
						|
                    _logger.debug("Deactivating view %s", one.name)
 | 
						|
                    # Disable it and set it to be enabled in multi theme mode
 | 
						|
                    one.view_id.write({
 | 
						|
                        "active": False,
 | 
						|
                        "was_active": True,
 | 
						|
                    })
 | 
						|
        # Clean Qweb cache
 | 
						|
        IrQweb = self.env["ir.qweb"]
 | 
						|
        IrQweb._get_asset_content.clear_cache(IrQweb)
 |