155 lines
5.8 KiB
Python
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
|