UnisKB/apps/system_manage/serializers/menu_setting.py

180 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# coding=utf-8
"""
@project: MaxKB
@AuthorCodex
@file menu_setting.py
@date2026/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}