Before this commit, it remove and reload the theme. Now we try to make a real update of view except for active field We cannot know if it is True into the template or if it is the default value.
285 lines
12 KiB
Python
285 lines
12 KiB
Python
# -*- 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):
|
|
_name = "ir.module.module"
|
|
_description = 'Module'
|
|
_inherit = _name
|
|
|
|
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].with_context(active_test=False).browse(imd_ids)
|
|
return records
|
|
|
|
def _convert_attachment(self, attach, website, **kw):
|
|
new_attach = {
|
|
'key': attach.key,
|
|
'public': True,
|
|
'res_model': 'ir.ui.view',
|
|
'type': 'url',
|
|
'name': attach.name,
|
|
'url': attach.url,
|
|
'website_id': website.id,
|
|
'theme_template_id': attach.id,
|
|
}
|
|
return new_attach
|
|
|
|
def _convert_view(self, view, website, **kw):
|
|
inherit = view.inherit_id
|
|
if view.inherit_id and view.inherit_id._name == 'theme.ir.ui.view':
|
|
inherit = view.inherit_id.copy_ids.filtered(lambda x: x.website_id == website)
|
|
if not inherit:
|
|
# inherit_id not yet created, add to the queue
|
|
return False
|
|
new_view = {
|
|
'type': view.type or 'qweb',
|
|
'name': view.name,
|
|
'arch': view.arch,
|
|
'key': view.key,
|
|
'inherit_id': inherit and inherit.id,
|
|
'arch_fs': view.arch_fs,
|
|
'priority': view.priority,
|
|
'active': view.active,
|
|
'theme_template_id': view.id,
|
|
'website_id': website.id,
|
|
}
|
|
|
|
if view.mode: # if not provided, it will be computed automatically (if inherit_id or not)
|
|
new_view['mode'] = view.mode
|
|
|
|
return new_view
|
|
|
|
def _convert_page(self, page, website, **kw):
|
|
new_page = {
|
|
'url': page.url,
|
|
'view_id': page.view_id.copy_ids.filtered(lambda x: x.website_id == website),
|
|
'website_indexed': page.website_indexed,
|
|
'theme_template_id': page.id,
|
|
}
|
|
return new_page
|
|
|
|
def _convert_menu(self, menu, website, **kw):
|
|
page_id = menu.page_id.copy_ids.filtered(lambda x: x.website_id == website)
|
|
parent_id = menu.copy_ids.filtered(lambda x: x.website_id == website)
|
|
new_menu = {
|
|
'name': menu.name,
|
|
'url': menu.url,
|
|
'page_id': page_id,
|
|
'new_window': menu.new_window,
|
|
'sequence': menu.sequence,
|
|
'parent_id': parent_id,
|
|
'theme_template_id': menu.id,
|
|
}
|
|
return new_menu
|
|
|
|
def _convert(self, model):
|
|
if model == 'ir.ui.view':
|
|
return self._convert_view
|
|
elif model == 'ir.attachment':
|
|
return self._convert_attachment
|
|
elif model == 'website.menu':
|
|
return self._convert_menu
|
|
elif model == 'website.page':
|
|
return self._convert_page
|
|
else:
|
|
_logger.error('No converter found for %s', model)
|
|
|
|
def _update_records(self, old, new):
|
|
# This function:
|
|
# create new record if not in old
|
|
# update old record if already exists
|
|
# delete old record that are not in new
|
|
website = self.env['website'].get_current_website()
|
|
model = old._name
|
|
created = self.env[model]
|
|
updated = self.env[model]
|
|
deleted = self.env[model]
|
|
|
|
remaining = new
|
|
last_len = -1
|
|
while (len(remaining) != last_len):
|
|
last_len = len(remaining)
|
|
for rec in remaining:
|
|
rec_data = self._convert(model)(rec, website)
|
|
if not rec_data:
|
|
_logger.info('Record queued: %s' % rec.name)
|
|
continue
|
|
|
|
find = rec.with_context(active_test=False).mapped('copy_ids').filtered(lambda m: m.website_id == website)
|
|
|
|
# special case for attachment
|
|
# if module B override attachment from dependence A, we update it
|
|
if not find and model == 'ir.attachment':
|
|
find = rec.copy_ids.search([('key', '=', rec.key), ('website_id', '=', website.id)])
|
|
|
|
if model == 'ir.ui.view':
|
|
rec_data.pop('active')
|
|
|
|
if find:
|
|
imd = self.env['ir.model.data'].search([('model', '=', find._name), ('res_id', '=', find.id)])
|
|
if imd and imd.noupdate:
|
|
_logger.info('Noupdate set for %s (%s)' % (find, imd))
|
|
continue
|
|
find.update(rec_data)
|
|
updated += find
|
|
else:
|
|
created += self.env[model].create(rec_data)
|
|
remaining -= rec
|
|
|
|
deleted = old - updated
|
|
deleted.unlink()
|
|
return (created, updated, deleted)
|
|
|
|
def _load_one_theme_module(self, website, with_update=True, **kw):
|
|
# load data from xml to template table
|
|
old_menus = self._get_module_data('theme.website.menu').with_context(active_test=False).mapped('copy_ids').filtered(lambda m: m.website_id == website)
|
|
old_pages = self._get_module_data('theme.website.page').with_context(active_test=False).mapped('copy_ids').filtered(lambda p: p.website_id == website)
|
|
old_attachs = self._get_module_data('theme.ir.attachment').with_context(active_test=False).mapped('copy_ids').filtered(lambda a: a.website_id == website)
|
|
old_views = self._get_module_data('theme.ir.ui.view').with_context(active_test=False).mapped('copy_ids').filtered(lambda v: v.website_id == website)
|
|
|
|
if with_update:
|
|
self.button_immediate_upgrade()
|
|
|
|
new_menus = self._get_module_data('theme.website.menu')
|
|
new_pages = self._get_module_data('theme.website.page')
|
|
new_attachs = self._get_module_data('theme.ir.attachment')
|
|
new_views = self._get_module_data('theme.ir.ui.view')
|
|
|
|
self._update_records(old_menus, new_menus)
|
|
self._update_records(old_pages, new_pages)
|
|
self._update_records(old_attachs, new_attachs)
|
|
self._update_records(old_views, new_views)
|
|
|
|
@api.multi
|
|
def _unload_one_theme_module(self, website):
|
|
self.ensure_one()
|
|
_logger.info('Unload theme %s for website %s from template.' % (self.mapped('name'), website.id))
|
|
menus = self._get_module_data('theme.website.menu')
|
|
menu_todel = menus.with_context(active_test=False).mapped('copy_ids').filtered(lambda m: m.website_id == website)
|
|
menu_todel.unlink()
|
|
|
|
pages = self._get_module_data('theme.website.page')
|
|
pages_todel = pages.with_context(active_test=False).mapped('copy_ids').filtered(lambda p: p.website_id == website)
|
|
pages_todel.unlink()
|
|
|
|
attachs = self._get_module_data('theme.ir.attachment')
|
|
attachs_todel = attachs.with_context(active_test=False).mapped('copy_ids').filtered(lambda a: a.website_id == website)
|
|
# double check - Some records that can be orphans or no more in the template view.
|
|
attachs_todel2 = self.env['ir.attachment'].with_context(active_test=False).search([('key', '=like', self.name + '_%'), ('website_id', '=', website.id)])
|
|
(attachs_todel + attachs_todel2).unlink()
|
|
|
|
views = self._get_module_data('theme.ir.ui.view')
|
|
views_todel = views.with_context(active_test=False).mapped('copy_ids').filtered(lambda v: v.website_id == website)
|
|
# double check - Some records that can be orphans or no more in the template view.
|
|
views_todel2 = self.env['ir.ui.view'].with_context(active_test=False).search([('key', '=like', self.name + '_%'), ('website_id', '=', website.id)])
|
|
(views_todel + views_todel2).unlink()
|
|
|
|
@api.multi
|
|
def _remove_theme_on_website(self, website):
|
|
self.ensure_one()
|
|
installed_deps = self + 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)
|
|
|
|
@api.multi
|
|
def _add_theme_on_website(self, website):
|
|
self.ensure_one()
|
|
mods_to_load = reversed(self + self.upstream_dependencies(exclude_states=('',)).filtered(lambda x: x.name.startswith('theme_')))
|
|
for mod in mods_to_load:
|
|
_logger.info('Load theme %s for website %s from template.' % (self.mapped('name'), website.id))
|
|
self._load_one_theme_module(website, with_update=False)
|
|
self.env['theme.utils']._post_copy(mod)
|
|
|
|
@api.multi
|
|
def button_choose_theme(self):
|
|
self.ensure_one()
|
|
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()
|
|
# reload registry to check if 'theme.utils'._<theme_name>_post_copy exists e.g.
|
|
self.env.reset()
|
|
self = self.env()[self._name].browse(self.id)
|
|
|
|
# Copy new theme from template table to real table
|
|
self._add_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()
|
|
self._load_one_theme_module(website, with_update=True)
|
|
|
|
@api.model
|
|
def update_list(self):
|
|
res = super(IrModuleModule, self).update_list()
|
|
|
|
IrAttachment = self.env['ir.attachment']
|
|
existing_urls = IrAttachment.search_read([['res_model', '=', self._name], ['type', '=', 'url']], ['url'])
|
|
existing_urls = [url_wrapped['url'] for url_wrapped in existing_urls]
|
|
|
|
for app in self.search([]):
|
|
terp = self.get_module_info(app.name)
|
|
images = terp.get('images', [])
|
|
for image in images:
|
|
image_path = os.path.join(app.name, image)
|
|
if image_path not in existing_urls:
|
|
image_name = os.path.basename(image_path)
|
|
IrAttachment.create({
|
|
'type': 'url',
|
|
'name': image_name,
|
|
'datas_fname': image_name,
|
|
'url': image_path,
|
|
'res_model': self._name,
|
|
'res_id': app.id,
|
|
})
|
|
return res
|