180 lines
6.8 KiB
Python
180 lines
6.8 KiB
Python
# coding=utf-8
|
||
"""
|
||
@project: MaxKB
|
||
@Author:Codex
|
||
@file: menu_setting.py
|
||
@date:2026/3/13
|
||
@desc: 菜单管理序列化器
|
||
"""
|
||
from collections import OrderedDict
|
||
|
||
from django.db import transaction, OperationalError, ProgrammingError
|
||
from rest_framework import serializers
|
||
|
||
from django.utils.translation import gettext_lazy as _
|
||
|
||
from common.constants.permission_constants import RoleConstants
|
||
from common.exception.app_exception import AppApiException
|
||
from system_manage.models import UserMenuSetting
|
||
from users.models import User
|
||
|
||
|
||
MENU_TREE = [
|
||
{
|
||
'id': 'main-navigation-group',
|
||
'label': '主导航',
|
||
'description': '对应 /admin/application 左侧主菜单',
|
||
'children': [
|
||
{'id': 'application', 'label': 'AI应用', 'description': '左侧主导航 / AI应用'},
|
||
{'id': 'mindmap', 'label': '思维导图', 'description': '左侧主导航 / 思维导图'},
|
||
{'id': 'knowledge', 'label': '知识库', 'description': '左侧主导航 / 知识库'},
|
||
{'id': 'tool', 'label': '工具管理', 'description': '左侧主导航 / 工具管理'},
|
||
{'id': 'model', 'label': '模型管理', 'description': '左侧主导航 / 模型管理'},
|
||
],
|
||
},
|
||
]
|
||
|
||
|
||
def get_leaf_ids(menu_tree):
|
||
leaf_ids = []
|
||
for item in menu_tree:
|
||
children = item.get('children') or []
|
||
if children:
|
||
leaf_ids.extend(get_leaf_ids(children))
|
||
else:
|
||
leaf_ids.append(item.get('id'))
|
||
return leaf_ids
|
||
|
||
|
||
ALL_MENU_LIST = get_leaf_ids(MENU_TREE)
|
||
|
||
|
||
class MenuSettingUserSerializer(serializers.Serializer):
|
||
id = serializers.UUIDField(required=True, label=_('User ID'))
|
||
nick_name = serializers.CharField(required=True, label=_('Nick name'))
|
||
username = serializers.CharField(required=True, label=_('Username'))
|
||
email = serializers.EmailField(required=False, allow_blank=True, allow_null=True, label=_('Email'))
|
||
is_active = serializers.BooleanField(required=True, label=_('Is active'))
|
||
|
||
|
||
class MenuSettingResponseSerializer(serializers.Serializer):
|
||
menu_tree = serializers.ListField(required=True, label=_('Menu tree'))
|
||
users = MenuSettingUserSerializer(many=True, required=True, label=_('User list'))
|
||
checked_map = serializers.DictField(
|
||
child=serializers.ListField(child=serializers.CharField(required=True)),
|
||
required=True,
|
||
label=_('User menu mapping')
|
||
)
|
||
|
||
|
||
class CurrentMenuSettingResponseSerializer(serializers.Serializer):
|
||
menu_list = serializers.ListField(child=serializers.CharField(required=True), required=True, label=_('Menu list'))
|
||
|
||
|
||
class MenuSettingSerializer(serializers.Serializer):
|
||
@staticmethod
|
||
def _is_system_admin(user_or_role):
|
||
role = getattr(user_or_role, 'role', user_or_role)
|
||
return role == RoleConstants.ADMIN.name
|
||
|
||
@staticmethod
|
||
def get_menu_tree():
|
||
return MENU_TREE
|
||
|
||
@staticmethod
|
||
def get_default_menu_list():
|
||
return ['knowledge']
|
||
|
||
@staticmethod
|
||
def _get_admin_menu_list():
|
||
return list(ALL_MENU_LIST)
|
||
|
||
@staticmethod
|
||
def _normalize_menu_list(menu_list):
|
||
valid_ids = set(ALL_MENU_LIST)
|
||
unique_menu_list = OrderedDict()
|
||
for menu_id in menu_list:
|
||
if menu_id in valid_ids:
|
||
unique_menu_list[menu_id] = True
|
||
return list(unique_menu_list.keys())
|
||
|
||
@staticmethod
|
||
def _get_user_queryset():
|
||
return User.objects.exclude(role=RoleConstants.ADMIN.name).order_by('create_time', 'username')
|
||
|
||
@staticmethod
|
||
def _get_checked_map(users=None):
|
||
checked_map = {}
|
||
if users is not None:
|
||
default_menu_list = MenuSettingSerializer.get_default_menu_list()
|
||
checked_map = {str(user.id): list(default_menu_list) for user in users}
|
||
try:
|
||
for setting in UserMenuSetting.objects.select_related('user').exclude(user__role=RoleConstants.ADMIN.name):
|
||
checked_map[str(setting.user_id)] = MenuSettingSerializer._normalize_menu_list(setting.menu_list or [])
|
||
except (ProgrammingError, OperationalError):
|
||
return checked_map
|
||
return checked_map
|
||
|
||
@staticmethod
|
||
def get_config():
|
||
user_queryset = list(MenuSettingSerializer._get_user_queryset())
|
||
users = list(user_queryset)
|
||
return {
|
||
'menu_tree': MenuSettingSerializer.get_menu_tree(),
|
||
'users': [{
|
||
'id': user.id,
|
||
'nick_name': user.nick_name,
|
||
'username': user.username,
|
||
'email': user.email,
|
||
'is_active': user.is_active
|
||
} for user in users],
|
||
'checked_map': MenuSettingSerializer._get_checked_map(user_queryset)
|
||
}
|
||
|
||
@staticmethod
|
||
def get_current_menu_list(user):
|
||
if MenuSettingSerializer._is_system_admin(user):
|
||
return MenuSettingSerializer._get_admin_menu_list()
|
||
user_id = getattr(user, 'id', user)
|
||
try:
|
||
setting = UserMenuSetting.objects.filter(user_id=user_id).first()
|
||
if setting is None:
|
||
return MenuSettingSerializer.get_default_menu_list()
|
||
return MenuSettingSerializer._normalize_menu_list(setting.menu_list or [])
|
||
except (ProgrammingError, OperationalError):
|
||
return MenuSettingSerializer.get_default_menu_list()
|
||
|
||
class Update(serializers.Serializer):
|
||
user_id = serializers.UUIDField(required=True, label=_('User ID'))
|
||
menu_list = serializers.ListField(
|
||
child=serializers.CharField(required=True),
|
||
required=True,
|
||
allow_empty=True,
|
||
label=_('Menu list')
|
||
)
|
||
|
||
def validate_user_id(self, value):
|
||
user = User.objects.filter(id=value).first()
|
||
if user is None:
|
||
raise AppApiException(1004, _('User does not exist'))
|
||
if MenuSettingSerializer._is_system_admin(user):
|
||
raise AppApiException(500, _('System administrator menu does not support configuration'))
|
||
return value
|
||
|
||
def validate_menu_list(self, value):
|
||
return MenuSettingSerializer._normalize_menu_list(value)
|
||
|
||
@transaction.atomic
|
||
def save(self):
|
||
self.is_valid(raise_exception=True)
|
||
user_id = self.validated_data.get('user_id')
|
||
menu_list = self.validated_data.get('menu_list')
|
||
default_menu_list = MenuSettingSerializer.get_default_menu_list()
|
||
if menu_list == default_menu_list:
|
||
UserMenuSetting.objects.filter(user_id=user_id).delete()
|
||
return {'user_id': str(user_id), 'menu_list': menu_list}
|
||
setting, _ = UserMenuSetting.objects.get_or_create(user_id=user_id)
|
||
setting.menu_list = menu_list
|
||
setting.save()
|
||
return {'user_id': str(user_id), 'menu_list': setting.menu_list}
|