odoo18/addons_extensions/menu_control_center/models/menu.py

155 lines
5.8 KiB
Python

from collections import defaultdict
from odoo import api, models, tools
from odoo.http import request
class IrUiMenu(models.Model):
_inherit = 'ir.ui.menu'
def _get_active_master_code(self):
return (request.session.get('active_master') if request else False) or self.env.context.get('active_master')
@api.model
@tools.ormcache('frozenset(self.env.user.groups_id.ids)', 'debug', 'self.env.uid', 'self._get_active_master_code() or ""')
def _visible_menu_ids(self, debug=False):
context = {'ir.ui.menu.full_list': True}
menus = self.with_context(context).search_fetch([], ['action', 'parent_id']).sudo()
active_master_code = self._get_active_master_code()
master_control = self.env['master.control'].sudo().search([('code', '=', active_master_code)], limit=1) if active_master_code else False
group_ids = set(self.env.user._get_group_ids())
if not debug:
group_ids -= {
self.env['ir.model.data']._xmlid_to_res_id('base.group_no_one', raise_if_not_found=False)
}
menus = menus.filtered(
lambda menu: not (menu.groups_id and group_ids.isdisjoint(menu.groups_id._ids))
)
if master_control:
if master_control.user_ids and self.env.user not in master_control.user_ids:
menus = self.browse()
else:
hidden_menu_ids = self._get_master_hidden_menu_ids(master_control) | self._get_hidden_menu_ids(master_control)
if hidden_menu_ids:
menus = menus.filtered(lambda menu: menu.id not in hidden_menu_ids)
visible = self._process_action_menus(menus)
return set(visible.ids)
@api.model
def load_menus_root(self):
root = super().load_menus_root()
visible_ids = self._visible_menu_ids(request.session.debug if request else False)
root['children'] = [
child for child in root.get('children', [])
if child['id'] in visible_ids
]
root['all_menu_ids'] = [
menu_id for menu_id in root.get('all_menu_ids', [])
if menu_id in visible_ids
]
return root
@api.model
def load_menus(self, debug):
all_menus = super().load_menus(debug)
visible_ids = self._visible_menu_ids(debug)
filtered_menus = {'root': dict(all_menus['root'])}
for menu_id, menu_data in all_menus.items():
if menu_id == 'root':
continue
if menu_id in visible_ids:
filtered_menus[menu_id] = dict(menu_data)
filtered_menus['root']['children'] = [
child_id for child_id in filtered_menus['root'].get('children', [])
if child_id in filtered_menus
]
for menu_id, menu_data in list(filtered_menus.items()):
if menu_id == 'root':
continue
menu_data['children'] = [
child_id for child_id in menu_data.get('children', [])
if child_id in filtered_menus
]
return filtered_menus
def _get_hidden_menu_ids(self, master_control):
access_controls = self.env['menu.access.control'].sudo().search([
('master_control_id', '=', master_control.id),
('user_ids', 'in', self.env.user.id),
])
hidden_lines = (access_controls.access_menu_line_ids | access_controls.access_sub_menu_line_ids).filtered(
lambda line: not line.show_menu
)
hidden_menu_ids = hidden_lines.mapped('menu_id').ids
if not hidden_menu_ids:
return set()
return set(
self.env['ir.ui.menu']
.sudo()
.with_context({'ir.ui.menu.full_list': True})
.search([('id', 'child_of', hidden_menu_ids)]).ids
)
def _get_master_hidden_menu_ids(self, master_control):
hidden_lines = (master_control.menu_line_ids | master_control.submenu_line_ids).filtered(
lambda line: not line.show_menu
)
hidden_menu_ids = hidden_lines.mapped('menu_id').ids
if not hidden_menu_ids:
return set()
return set(
self.env['ir.ui.menu']
.sudo()
.with_context({'ir.ui.menu.full_list': True})
.search([('id', 'child_of', hidden_menu_ids)]).ids
)
def _process_action_menus(self, menus):
actions_by_model = defaultdict(set)
for action in menus.mapped('action'):
if action:
actions_by_model[action._name].add(action.id)
existing_actions = {
action
for model_name, action_ids in actions_by_model.items()
for action in self.env[model_name].browse(action_ids).exists()
}
action_menus = menus.filtered(lambda menu: menu.action and menu.action in existing_actions)
folder_menus = menus - action_menus
visible = self.browse()
access_model = self.env['ir.model.access']
model_by_type = {
'ir.actions.act_window': 'res_model',
'ir.actions.report': 'model',
'ir.actions.server': 'model_name',
}
prefetch_ids = defaultdict(list)
for action in action_menus.mapped('action'):
prefetch_ids[action._name].append(action.id)
for menu in action_menus:
action = menu.action.with_prefetch(prefetch_ids[action._name])
model_name = action._name in model_by_type and action[model_by_type[action._name]]
if not model_name or access_model.check(model_name, 'read', False):
visible += menu
parent = menu.parent_id
while parent and parent in folder_menus and parent not in visible:
visible += parent
parent = parent.parent_id
return visible