summaryrefslogtreecommitdiff
path: root/addons/website_theme_install/models/ir_module_module.py
diff options
context:
space:
mode:
authorJeremy Kersten <jke@odoo.com>2018-08-12 23:17:24 +0200
committerJeremy Kersten <jke@odoo.com>2018-08-13 20:16:34 +0200
commitc0968e68eda55df624fb94016d036a2af598b10c (patch)
tree2bc27d7931036dc85bcbdd693db61a5803b44670 /addons/website_theme_install/models/ir_module_module.py
parent066cfc9598a307a48b86104f4bf861a58de09b41 (diff)
[ADD] website_theme_install: try to make theme multi website compliant
From now, when you install a theme, it load the data from xml to template table theme [ir.ui.view|ir.attachment|website.page|website.menu]. Data are only copied from this template table into the real table when you choose a theme on a website; Making them website_specific and with a link to the original to allow futur update. A special case is done to create theme.ir.ui.view when you are installing a theme, even if you continue to use template tag to create quick view. Co-authored-by: Derie Romain <rde@odoo.com> Co-authored-by: Kersten Jérémy <jke@odoo.com>
Diffstat (limited to 'addons/website_theme_install/models/ir_module_module.py')
-rw-r--r--addons/website_theme_install/models/ir_module_module.py272
1 files changed, 146 insertions, 126 deletions
diff --git a/addons/website_theme_install/models/ir_module_module.py b/addons/website_theme_install/models/ir_module_module.py
index 560bd37a932..7207a613ade 100644
--- a/addons/website_theme_install/models/ir_module_module.py
+++ b/addons/website_theme_install/models/ir_module_module.py
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-import os
import logging
+import os
from odoo import api, fields, models
-
_logger = logging.getLogger(__name__)
@@ -16,71 +15,174 @@ class IrModuleModule(models.Model):
image_ids = fields.One2many('ir.attachment', 'res_id',
domain=[('res_model', '=', _name), ('mimetype', '=like', 'image/%')],
string='Screenshots', readonly=True)
+ # for kanban view
is_installed_on_current_website = fields.Boolean(compute='_compute_is_installed_on_current_website')
@api.multi
def _compute_is_installed_on_current_website(self):
for module in self:
- module.is_installed_on_current_website = module == self.env['website'].get_current_website().installed_theme_id
+ module.is_installed_on_current_website = module == self.env['website'].get_current_website().theme_id
@api.multi
def write(self, vals):
- if vals.get('state') == 'installed':
- self._handle_auto_installs()
-
+ if vals.get('state') == 'installed' and self.name.startswith('theme_'):
+ _logger.info('Module %s has been loaded as theme template' % self.name)
return super(IrModuleModule, self).write(vals)
@api.multi
- def _assign_views(self):
- IrModelData = self.env['ir.model.data']
- for module in self:
- views = self.env['ir.ui.view'].browse(IrModelData.search([('module', '=', module.name),
- ('model', '=', 'ir.ui.view')]).mapped('res_id'))
- views.write({
- 'theme_id': module.id
- })
-
- @api.model
- def _handle_auto_installs(self):
- for module in self.search([('auto_install', '=', True), ('name', '=like', 'theme%'), ('state', 'in', ('installed', 'to install'))]):
- theme_deps = module.get_upstream_theme_dependencies()
- websites = self.env['website'].search([]).filtered(lambda w: len(theme_deps - w.theme_ids) == 0)
- if websites:
- _logger.info('auto-loading %s on %s', module.name, websites.mapped('name'))
- websites.write({'theme_ids': [(4, module.id, 0)]})
- module._assign_views()
-
- # put demo date on first website
- module._make_demo_data_website_specific(websites[0])
-
- @api.multi
def _get_module_data(self, model_name):
IrModelData = self.env['ir.model.data']
records = self.env[model_name]
for module in self:
- records |= self.env[model_name].browse(IrModelData.search([('module', '=', module.name), ('model', '=', model_name)]).mapped('res_id'))
-
+ imd_ids = IrModelData.search([('module', '=', module.name), ('model', '=', model_name)]).mapped('res_id')
+ records |= self.env[model_name].browse(imd_ids)
return records
@api.multi
- def _make_demo_data_website_specific(self, website):
- for module in self:
- menus = module._get_module_data('website.menu')
- menus.with_context(no_cow=True).write({'website_id': website.id})
-
- pages = module._get_module_data('website.page')
- pages.with_context(no_cow=True).write({'website_id': website.id})
- pages.with_context(no_cow=True).mapped('view_id').write({'website_id': website.id})
+ def _load_one_theme_module(self, website, loaded):
+ # loaded is a dict updated in place !
+ # keep previous record created to update overrided record
+ _logger.info('Load theme %s for website %s from template.' % (self.mapped('name'), website.id))
+
+ for attach in self._get_module_data('theme.ir.attachment'):
+ already_create = loaded['attachments'].filtered(lambda x: x.key == attach.key)
+ new_attach = {
+ 'public': True,
+ 'res_model': 'ir.ui.view',
+ 'type': 'url',
+ 'name': attach.name,
+ 'url': attach.url,
+ 'website_id': website.id,
+ 'theme_template_id': attach.id,
+ }
+ if already_create:
+ already_create.update(new_attach)
+ else: # if module B override attachment from dependence A
+ loaded['attachments'] += self.env['ir.attachment'].create(new_attach)
+
+ for view in self._get_module_data('theme.ir.ui.view'):
+ if view.inherit_id and view.inherit_id._name == 'theme.ir.ui.view':
+ view.inherit_id = loaded['views'].filtered(lambda x: x.theme_template_id == view.inherit_id)
+
+ new_view = {
+ 'type': view.type or 'qweb',
+ 'name': view.name,
+ 'arch': view.arch,
+ 'key': view.key,
+ 'arch': view.arch,
+ 'arch_fs': view.arch_fs,
+ 'priority': view.priority,
+ 'active': view.active,
+ 'inherit_id': view.inherit_id and view.inherit_id.id,
+ 'theme_template_id': view.id,
+ 'website_id': website.id,
+ }
+ loaded['views'] += self.env['ir.ui.view'].create(new_view)
+
+ for page in self._get_module_data('theme.website.page'):
+ new_page = {
+ 'url': page.url,
+ 'view_id': loaded['views'].filtered(lambda x: x.theme_template_id == page.view_id).id,
+ 'website_indexed': page.website_indexed,
+ 'theme_template_id': page.id,
+ }
+ loaded['pages'] += self.env['website.page'].create(new_page)
+
+ for menu in self._get_module_data('theme.website.menu'):
+ new_menu = {
+ 'name': menu.name,
+ 'url': menu.url,
+ 'page_id': loaded['pages'].filtered(lambda x: x.theme_template_id == menu.page_id).id,
+ 'new_window': menu.new_window,
+ 'sequence': menu.sequence,
+ 'parent_id': loaded['menus'].filtered(lambda x: x.theme_template_id == menu.parent_id).id,
+ 'theme_template_id': menu.id,
+ }
+ loaded['menus'] += self.env['website.menu'].create(new_menu)
+
+ return True
@api.multi
- def _remove_website_specific_demo_data(self, website):
+ def _unload_one_theme_module(self, website):
+ _logger.info('Unload theme %s for website %s from template.' % (self.mapped('name'), website.id))
+
for module in self:
- menus = module._get_module_data('website.menu')
- menus.filtered(lambda menu: menu.website_id == website).unlink()
+ menus = module._get_module_data('theme.website.menu')
+ menu_todel = menus.mapped('copy_ids').filtered(lambda m: m.website_id == website)
+ menu_todel.unlink()
+
+ pages = module._get_module_data('theme.website.page')
+ pages_todel = pages.mapped('copy_ids').filtered(lambda p: p.website_id == website)
+ pages_todel.unlink()
+
+ attachs = module._get_module_data('theme.ir.attachment')
+ atachs_todel = attachs.mapped('copy_ids').filtered(lambda a: a.website_id == website)
+ atachs_todel.unlink()
+
+ views = module._get_module_data('theme.ir.ui.view')
+ views_todel = views.mapped('copy_ids').filtered(lambda v: v.website_id == website)
+ views_todel.unlink()
+
+ def _remove_theme_on_website(self, website):
+ installed_deps = website.theme_id.upstream_dependencies(exclude_states=('',)).filtered(lambda x: x.name.startswith('theme_'))
+ for mod in installed_deps:
+ mod._unload_one_theme_module(website)
+
+ def _copy_theme_on_website(self, website):
+ loaded = {
+ 'views': self.env['ir.ui.view'],
+ 'attachments': self.env['ir.attachment'],
+ 'pages': self.env['website.page'],
+ 'menus': self.env['website.menu'],
+ }
+ mods_to_load = reversed(self + self.upstream_dependencies(exclude_states=('',)).filtered(lambda x: x.name.startswith('theme_')))
+ for mod in mods_to_load:
+ mod._load_one_theme_module(website, loaded)
+ self.env['theme.utils']._post_copy(mod)
+
+ @api.multi
+ def button_choose_theme(self):
+ website = self.env['website'].get_current_website()
+
+ # Unload previous theme
+ if website.theme_id:
+ website.theme_id._remove_theme_on_website(website)
+
+ website.theme_id = self
+
+ # create template data of missing theme
+ next_action = False
+ if self.state != 'installed':
+ next_action = self.button_immediate_install()
+
+ # Copy new theme from template table to real table
+ self._copy_theme_on_website(website)
+
+ # Alter next action for redirect
+ if not next_action:
+ next_action = website.button_go_website()
+ if next_action.get('tag') == 'reload' and not next_action.get('params', {}).get('menu_id'):
+ next_action = self.env.ref('website.action_website').read()[0]
+
+ return next_action
+
+ def button_remove_theme(self):
+ website = self.env['website'].get_current_website()
+ self._remove_theme_on_website(website)
+ website.theme_id = False
+
+ def button_refresh_theme(self):
+ website = self.env['website'].get_current_website()
+ # load data from xml to template table
+ self.button_immediate_upgrade()
+
+ # delete current theme
+ # todo: quid of no_update record?
+ self.button_remove_theme()
- pages = module._get_module_data('website.page')
- pages.filtered(lambda page: page.website_id == website).unlink()
+ # copy data from template table to real table
+ self._copy_theme_on_website(website)
@api.model
def update_list(self):
@@ -105,86 +207,4 @@ class IrModuleModule(models.Model):
'res_model': self._name,
'res_id': app.id,
})
-
return res
-
- def get_upstream_theme_dependencies(self):
- upstream_deps = self.upstream_dependencies(exclude_states=('uninstallable', 'to remove'))
- upstream_theme_deps = upstream_deps.filtered(lambda mod: any(mod.name.startswith(keyword) for keyword in ('theme_', 'snippet_', 'website_animate')))
- return upstream_theme_deps
-
- @api.multi
- def button_choose_theme(self):
- theme_category = self.env.ref('base.module_category_theme', False)
- theme_hidden_category = self.env.ref('base.module_category_theme_hidden', False)
-
- theme_category_id = theme_category.id if theme_category else 0
- hidden_categories_ids = [theme_hidden_category.id if theme_hidden_category else 0]
- current_website = self.env['website'].get_current_website()
-
- themes_to_uninstall = self.search([ # Uninstall the theme(s) which is (are) installed
- ('state', '=', 'installed'),
- ('category_id', 'not in', hidden_categories_ids),
- ('id', 'in', current_website.theme_ids.ids),
- '|', ('category_id', '=', theme_category_id), ('category_id.parent_id', '=', theme_category_id)
- ])
-
- if themes_to_uninstall:
- themes_to_uninstall.button_immediate_uninstall()
-
- modules_belonging_to_theme = self + self.get_upstream_theme_dependencies()
- current_website.installed_theme_id = self
- current_website.theme_ids |= modules_belonging_to_theme
-
- next_action = self.button_immediate_install() # Then install the new chosen one
- modules_belonging_to_theme._assign_views()
- modules_belonging_to_theme._make_demo_data_website_specific(current_website)
- self._handle_auto_installs()
- _logger.info('installed themes %s on %s', modules_belonging_to_theme.mapped('name'), current_website.name)
-
- if next_action.get('tag') == 'reload' and not next_action.get('params', {}).get('menu_id'):
- next_action = self.env.ref('website.action_website').read()[0]
-
- return next_action
-
- @api.multi
- def button_uninstall(self):
- if not any(mod.name.startswith('theme_') for mod in self):
- return super(IrModuleModule, self).button_uninstall()
-
- # only one theme can be uninstalled
- self.ensure_one()
-
- Website = self.env['website']
- current_website = Website.get_current_website()
- if Website.search_count([('theme_ids', 'in', self.id)]) > 1:
- modules_belonging_to_theme = self + self.get_upstream_theme_dependencies() + self.downstream_dependencies()
- current_website.installed_theme_id -= modules_belonging_to_theme
- current_website.theme_ids -= modules_belonging_to_theme
- modules_belonging_to_theme._remove_website_specific_demo_data(current_website)
- _logger.info('removed themes %s from %s', modules_belonging_to_theme.mapped('name'), current_website.name)
- return True
- else:
- uninstalled_modules = self + self.downstream_dependencies()
- res = super(IrModuleModule, self).button_uninstall()
-
- for website in Website.search([]):
- website.installed_theme_id -= uninstalled_modules
- website.theme_ids -= uninstalled_modules
- _logger.info('removed themes %s from %s', uninstalled_modules.mapped('name'), website.name)
-
- # Attempt to uninstall upstream dependencies. This is
- # necessary for uninstalling e.g. theme_zap, when doing so
- # theme_treehouse should also be removed from the current
- # website. This way the user can install a completely new
- # theme.
- #
- # Make sure to only uninstall every module once with
- # context. Otherwise it might get removed from the current
- # website the first time and the second time it might end
- # up being wrongly uninstalled.
- if self._context.get('uninstall_upstream') is not False:
- for upstream_dependency in self.get_upstream_theme_dependencies().filtered(lambda mod: mod.name.startswith('theme_')):
- upstream_dependency.with_context(uninstall_upstream=False).button_uninstall()
-
- return res