summaryrefslogtreecommitdiff
path: root/addons/website/models/website_menu.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/website/models/website_menu.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/website/models/website_menu.py')
-rw-r--r--addons/website/models/website_menu.py206
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