diff options
Diffstat (limited to 'addons/website_theme_install/models')
| -rw-r--r-- | addons/website_theme_install/models/__init__.py | 4 | ||||
| -rw-r--r-- | addons/website_theme_install/models/ir_module_module.py | 191 | ||||
| -rw-r--r-- | addons/website_theme_install/models/res_company.py | 28 | ||||
| -rw-r--r-- | addons/website_theme_install/models/res_config_settings.py | 14 | ||||
| -rw-r--r-- | addons/website_theme_install/models/theme_models.py | 94 | ||||
| -rw-r--r-- | addons/website_theme_install/models/website.py | 25 |
6 files changed, 335 insertions, 21 deletions
diff --git a/addons/website_theme_install/models/__init__.py b/addons/website_theme_install/models/__init__.py index de58fda6e31..0e35edfc5eb 100644 --- a/addons/website_theme_install/models/__init__.py +++ b/addons/website_theme_install/models/__init__.py @@ -2,3 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import ir_module_module +from . import res_company +from . import res_config_settings +from . import theme_models +from . import website diff --git a/addons/website_theme_install/models/ir_module_module.py b/addons/website_theme_install/models/ir_module_module.py index 5350abea437..7207a613ade 100644 --- a/addons/website_theme_install/models/ir_module_module.py +++ b/addons/website_theme_install/models/ir_module_module.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import logging import os from odoo import api, fields, models +_logger = logging.getLogger(__name__) class IrModuleModule(models.Model): @@ -13,6 +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().theme_id + + @api.multi + def write(self, vals): + 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 _get_module_data(self, model_name): + IrModelData = self.env['ir.model.data'] + records = self.env[model_name] + + for module in self: + 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 _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 _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('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() + + # copy data from template table to real table + self._copy_theme_on_website(website) @api.model def update_list(self): @@ -37,25 +207,4 @@ class IrModuleModule(models.Model): 'res_model': self._name, 'res_id': app.id, }) - return res - - @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] - - self.search([ # Uninstall the theme(s) which is (are) installed - ('state', '=', 'installed'), - ('category_id', 'not in', hidden_categories_ids), - '|', ('category_id', '=', theme_category_id), ('category_id.parent_id', '=', theme_category_id) - ]).button_immediate_uninstall() - - next_action = self.button_immediate_install() # Then install the new chosen one - 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 diff --git a/addons/website_theme_install/models/res_company.py b/addons/website_theme_install/models/res_company.py new file mode 100644 index 00000000000..f125a87dca3 --- /dev/null +++ b/addons/website_theme_install/models/res_company.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models +from ast import literal_eval + + +class ResCompany(models.Model): + _inherit = 'res.company' + + def _compute_website_theme_onboarding_done(self): + """ The step is marked as done if one theme is installed. """ + # we need the same domain as the existing action + action = self.env.ref('website_theme_install.theme_install_kanban_action').read()[0] + domain = literal_eval(action['domain']) + domain.append(('state', '=', 'installed')) + installed_themes_count = self.env['ir.module.module'].sudo().search_count(domain) + for record in self: + record.website_theme_onboarding_done = (installed_themes_count > 0) + + website_theme_onboarding_done = fields.Boolean("Onboarding website theme step done", + compute='_compute_website_theme_onboarding_done') + + @api.model + def action_open_website_theme_selector(self): + action = self.env.ref('website_theme_install.theme_install_kanban_action').read()[0] + action['target'] = 'new' + return action diff --git a/addons/website_theme_install/models/res_config_settings.py b/addons/website_theme_install/models/res_config_settings.py new file mode 100644 index 00000000000..f080cea9575 --- /dev/null +++ b/addons/website_theme_install/models/res_config_settings.py @@ -0,0 +1,14 @@ +# coding: utf-8 +from odoo import models + + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + def install_theme_on_current_website(self): + self.website_id._force() + return { + 'type': 'ir.actions.act_url', + 'url': '/web#action=website_theme_install.theme_install_kanban_action', + 'target': 'self', + } diff --git a/addons/website_theme_install/models/theme_models.py b/addons/website_theme_install/models/theme_models.py new file mode 100644 index 00000000000..428fa55a559 --- /dev/null +++ b/addons/website_theme_install/models/theme_models.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import logging +from odoo import fields, models +from odoo.modules.module import get_resource_from_path + +_logger = logging.getLogger(__name__) + + +class ThemeView(models.Model): + _name = 'theme.ir.ui.view' + + def compute_arch_fs(self): + path_info = get_resource_from_path(self._context['install_filename']) + if path_info: + return '/'.join(path_info[0:2]) + + name = fields.Char(required=True) + key = fields.Char() + type = fields.Char() + priority = fields.Integer(default=16, required=True) + active = fields.Boolean(default=True) + arch = fields.Text() + arch_fs = fields.Char(default=compute_arch_fs) + inherit_id = fields.Reference(selection=[('ir.ui.view', 'ir.ui.view'), ('theme.ir.ui.view', 'theme.ir.ui.view')]) + copy_ids = fields.One2many('ir.ui.view', 'theme_template_id', 'Views using a copy of me', copy=False, readonly=True) + + +class ThemeAttachment(models.Model): + _name = 'theme.ir.attachment' + + name = fields.Char(required=True) + key = fields.Char(required=True) + url = fields.Char() + copy_ids = fields.One2many('ir.attachment', 'theme_template_id', 'Attachment using a copy of me', copy=False, readonly=True) + + +class ThemeMenu(models.Model): + _name = 'theme.website.menu' + + name = fields.Char(required=True) + url = fields.Char(default='') + page_id = fields.Many2one('theme.website.page', ondelete='cascade') + new_window = fields.Boolean('New Window') + sequence = fields.Integer() + parent_id = fields.Many2one('theme.website.menu', index=True, ondelete="cascade") + copy_ids = fields.One2many('website.menu', 'theme_template_id', 'Menu using a copy of me', copy=False, readonly=True) + + +class ThemePage(models.Model): + _name = 'theme.website.page' + + url = fields.Char() + view_id = fields.Many2one('theme.ir.ui.view', required=True, ondelete="cascade") + website_indexed = fields.Boolean('Page Indexed', default=True) + copy_ids = fields.One2many('website.page', 'theme_template_id', 'Theme using a copy of me', copy=False, readonly=True) + + +class Theme(models.AbstractModel): + _name = 'theme.utils' + _auto = False + + def _post_copy(self, mod): + theme_post_copy = '_%s_post_copy' % mod.name + if hasattr(self, theme_post_copy): + _logger.info('Executing method %s' % theme_post_copy) + method = getattr(self, theme_post_copy) + return method() + + +class IrUiView(models.Model): + _inherit = 'ir.ui.view' + + theme_template_id = fields.Many2one('theme.ir.ui.view') + + +class IrAttachment(models.Model): + _inherit = 'ir.attachment' + + key = fields.Char() + theme_template_id = fields.Many2one('theme.ir.attachment') + + +class WebiteMenu(models.Model): + _inherit = 'website.menu' + + theme_template_id = fields.Many2one('theme.website.menu') + + +class WebsitePage(models.Model): + _inherit = 'website.page' + + theme_template_id = fields.Many2one('theme.website.page') diff --git a/addons/website_theme_install/models/website.py b/addons/website_theme_install/models/website.py new file mode 100644 index 00000000000..46ee9df91e2 --- /dev/null +++ b/addons/website_theme_install/models/website.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models + + +class Website(models.Model): + _name = "website" + _inherit = _name + + def button_view_theme(self): + self._force() + return { + 'type': 'ir.actions.act_url', + 'url': '/web#action=website_theme_install.theme_install_kanban_action', + 'target': 'self', + } + + def button_go_website(self): + self._force() + return { + 'type': 'ir.actions.act_url', + 'url': '/', + 'target': 'self', + } |
