diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/website/models/website_menu.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/website/models/website_menu.py')
| -rw-r--r-- | addons/website/models/website_menu.py | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/addons/website/models/website_menu.py b/addons/website/models/website_menu.py new file mode 100644 index 00000000..8b6648c4 --- /dev/null +++ b/addons/website/models/website_menu.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import werkzeug.exceptions + +from odoo import api, fields, models +from odoo.tools.translate import html_translate + + +class Menu(models.Model): + + _name = "website.menu" + _description = "Website Menu" + + _parent_store = True + _order = "sequence, id" + + def _default_sequence(self): + menu = self.search([], limit=1, order="sequence DESC") + return menu.sequence or 0 + + def _compute_field_is_mega_menu(self): + for menu in self: + menu.is_mega_menu = bool(menu.mega_menu_content) + + def _set_field_is_mega_menu(self): + for menu in self: + if menu.is_mega_menu: + if not menu.mega_menu_content: + default_content = self.env['ir.ui.view']._render_template('website.s_mega_menu_multi_menus') + menu.mega_menu_content = default_content.decode() + else: + menu.mega_menu_content = False + menu.mega_menu_classes = False + + name = fields.Char('Menu', required=True, translate=True) + url = fields.Char('Url', default='') + page_id = fields.Many2one('website.page', 'Related Page', ondelete='cascade') + new_window = fields.Boolean('New Window') + sequence = fields.Integer(default=_default_sequence) + website_id = fields.Many2one('website', 'Website', ondelete='cascade') + parent_id = fields.Many2one('website.menu', 'Parent Menu', index=True, ondelete="cascade") + child_id = fields.One2many('website.menu', 'parent_id', string='Child Menus') + parent_path = fields.Char(index=True) + is_visible = fields.Boolean(compute='_compute_visible', string='Is Visible') + group_ids = fields.Many2many('res.groups', string='Visible Groups', + help="User need to be at least in one of these groups to see the menu") + is_mega_menu = fields.Boolean(compute=_compute_field_is_mega_menu, inverse=_set_field_is_mega_menu) + mega_menu_content = fields.Html(translate=html_translate, sanitize=False, prefetch=True) + mega_menu_classes = fields.Char() + + def name_get(self): + if not self._context.get('display_website') and not self.env.user.has_group('website.group_multi_website'): + return super(Menu, self).name_get() + + res = [] + for menu in self: + menu_name = menu.name + if menu.website_id: + menu_name += ' [%s]' % menu.website_id.name + res.append((menu.id, menu_name)) + return res + + @api.model + def create(self, vals): + ''' In case a menu without a website_id is trying to be created, we duplicate + it for every website. + Note: Particulary useful when installing a module that adds a menu like + /shop. So every website has the shop menu. + Be careful to return correct record for ir.model.data xml_id in case + of default main menus creation. + ''' + self.clear_caches() + # Only used when creating website_data.xml default menu + if vals.get('url') == '/default-main-menu': + return super(Menu, self).create(vals) + + if 'website_id' in vals: + return super(Menu, self).create(vals) + elif self._context.get('website_id'): + vals['website_id'] = self._context.get('website_id') + return super(Menu, self).create(vals) + else: + # create for every site + for website in self.env['website'].search([]): + w_vals = dict(vals, **{ + 'website_id': website.id, + 'parent_id': website.menu_id.id, + }) + res = super(Menu, self).create(w_vals) + # if creating a default menu, we should also save it as such + default_menu = self.env.ref('website.main_menu', raise_if_not_found=False) + if default_menu and vals.get('parent_id') == default_menu.id: + res = super(Menu, self).create(vals) + return res # Only one record is returned but multiple could have been created + + def write(self, values): + res = super().write(values) + if 'website_id' in values or 'group_ids' in values or 'sequence' in values: + self.clear_caches() + return res + + def unlink(self): + self.clear_caches() + default_menu = self.env.ref('website.main_menu', raise_if_not_found=False) + menus_to_remove = self + for menu in self.filtered(lambda m: default_menu and m.parent_id.id == default_menu.id): + menus_to_remove |= self.env['website.menu'].search([('url', '=', menu.url), + ('website_id', '!=', False), + ('id', '!=', menu.id)]) + return super(Menu, menus_to_remove).unlink() + + def _compute_visible(self): + for menu in self: + visible = True + if menu.page_id and not menu.user_has_groups('base.group_user') and \ + (not menu.page_id.sudo().is_visible or + (not menu.page_id.view_id._handle_visibility(do_raise=False) and + menu.page_id.view_id.visibility != "password")): + visible = False + menu.is_visible = visible + + @api.model + def clean_url(self): + # clean the url with heuristic + if self.page_id: + url = self.page_id.sudo().url + else: + url = self.url + if url and not self.url.startswith('/'): + if '@' in self.url: + if not self.url.startswith('mailto'): + url = 'mailto:%s' % self.url + elif not self.url.startswith('http'): + url = '/%s' % self.url + return url + + # would be better to take a menu_id as argument + @api.model + def get_tree(self, website_id, menu_id=None): + def make_tree(node): + is_homepage = bool(node.page_id and self.env['website'].browse(website_id).homepage_id.id == node.page_id.id) + menu_node = { + 'fields': { + 'id': node.id, + 'name': node.name, + 'url': node.page_id.url if node.page_id else node.url, + 'new_window': node.new_window, + 'is_mega_menu': node.is_mega_menu, + 'sequence': node.sequence, + 'parent_id': node.parent_id.id, + }, + 'children': [], + 'is_homepage': is_homepage, + } + for child in node.child_id: + menu_node['children'].append(make_tree(child)) + return menu_node + + menu = menu_id and self.browse(menu_id) or self.env['website'].browse(website_id).menu_id + return make_tree(menu) + + @api.model + def save(self, website_id, data): + def replace_id(old_id, new_id): + for menu in data['data']: + if menu['id'] == old_id: + menu['id'] = new_id + if menu['parent_id'] == old_id: + menu['parent_id'] = new_id + to_delete = data['to_delete'] + if to_delete: + self.browse(to_delete).unlink() + for menu in data['data']: + mid = menu['id'] + # new menu are prefixed by new- + if isinstance(mid, str): + new_menu = self.create({'name': menu['name'], 'website_id': website_id}) + replace_id(mid, new_menu.id) + for menu in data['data']: + menu_id = self.browse(menu['id']) + # if the url match a website.page, set the m2o relation + # except if the menu url is '#', meaning it will be used as a menu container, most likely for a dropdown + if menu['url'] == '#': + if menu_id.page_id: + menu_id.page_id = None + else: + domain = self.env["website"].website_domain(website_id) + [ + "|", + ("url", "=", menu["url"]), + ("url", "=", "/" + menu["url"]), + ] + page = self.env["website.page"].search(domain, limit=1) + if page: + menu['page_id'] = page.id + menu['url'] = page.url + elif menu_id.page_id: + try: + # a page shouldn't have the same url as a controller + rule, arguments = self.env['ir.http']._match(menu['url']) + menu_id.page_id = None + except werkzeug.exceptions.NotFound: + menu_id.page_id.write({'url': menu['url']}) + menu_id.write(menu) + + return True |
