From 20ef1fc146e5ce1dc88f6469b58333366a9c0ba1 Mon Sep 17 00:00:00 2001 From: Bai Date: Sun, 28 Dec 2025 00:57:17 +0800 Subject: [PATCH] perf: UserPermAssetTreeAPI rename asset-tree and node-tree --- apps/assets/api/mixin.py | 6 +- apps/perms/api/user_permission/assets.py | 6 +- apps/perms/api/user_permission/tree.py | 178 +++++++++++++---------- apps/perms/tree.py | 14 +- 4 files changed, 117 insertions(+), 87 deletions(-) diff --git a/apps/assets/api/mixin.py b/apps/assets/api/mixin.py index c8e5a7008..8fb4a1f80 100644 --- a/apps/assets/api/mixin.py +++ b/apps/assets/api/mixin.py @@ -12,7 +12,7 @@ class SerializeToTreeNodeMixin: request: Request @timeit - def serialize_nodes(self, nodes: List[AssetTreeNode], with_asset_amount=False, expand_level=1, with_assets=False): + def serialize_nodes(self, nodes: List[AssetTreeNode], with_asset_amount=False, expand_level=1, tree_type='node'): if not nodes: return [] @@ -24,9 +24,9 @@ class SerializeToTreeNodeMixin: return v def is_parent(node: AssetTreeNode): - if with_assets: + if tree_type == 'asset': return node.assets_amount > 0 or not node.is_leaf - else: + else: # tree_type == 'node' return not node.is_leaf data = [ diff --git a/apps/perms/api/user_permission/assets.py b/apps/perms/api/user_permission/assets.py index 317703ea6..8695b3e2c 100644 --- a/apps/perms/api/user_permission/assets.py +++ b/apps/perms/api/user_permission/assets.py @@ -13,7 +13,7 @@ from perms import serializers from perms.pagination import NodePermedAssetPagination, AllPermedAssetPagination from perms.utils import UserPermAssetUtil, PermAssetDetailUtil from perms.utils.utils import UserPermUtil -from perms.tree import PermTreeNode +from perms.tree import UserPermAssetTreeNode from .mixin import ( SelfOrPKUserMixin ) @@ -77,10 +77,10 @@ class UserAllPermedAssetsApi(BaseUserPermedAssetsApi): node_id = self.request.query_params.get('node_id') - if node_id == PermTreeNode.SpecialKey.FAVORITE: + if node_id == UserPermAssetTreeNode.SpecialKey.FAVORITE: return UserPermUtil.get_favorite_assets(user=self.user) - if node_id == PermTreeNode.SpecialKey.UNGROUPED: + if node_id == UserPermAssetTreeNode.SpecialKey.UNGROUPED: _util = UserPermUtil(user=self.user) return _util.get_ungrouped_assets() diff --git a/apps/perms/api/user_permission/tree.py b/apps/perms/api/user_permission/tree.py index 7a0063db0..c92ddec02 100644 --- a/apps/perms/api/user_permission/tree.py +++ b/apps/perms/api/user_permission/tree.py @@ -11,7 +11,7 @@ from orgs.utils import current_org from assets.api import SerializeToTreeNodeMixin from assets.models import Node, FavoriteAsset, Asset from assets.tree.asset_tree import AssetTreeNodeAsset -from perms.tree import UserPermTree, PermTreeNode +from perms.tree import UserPermAssetTree, UserPermAssetTreeNode from perms.utils.utils import UserPermUtil from .mixin import SelfOrPKUserMixin @@ -23,66 +23,90 @@ __all__ = [ ] +class RenderTreeType: + NODE = 'node' + ASSET = 'asset' + + def __init__(self, tp): + if tp not in [self.NODE, self.ASSET]: + raise ValueError(f'Invalid tree type: {tp}') + self._type = tp + + def is_asset_tree(self): + return self._type == self.ASSET + + def is_node_tree(self): + return self._type == self.NODE + + def __str__(self): + return self._type + + class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, ListAPIView): + def get_query_value(self, query_key): + query_value = self.request.query_params.get(query_key) + if query_value: + return query_value + + search = self.request.query_params.get('search', '') + if not search: + return None + + search_list = search.split() + for _search in search_list: + if f'{query_key}:' not in _search: + continue + query_value = _search.replace(f'{query_key}:', '').strip() + break + return query_value + + @property + def render_tree_type(self): + tree_type = self.get_query_value('tree_type') + + if tree_type: + return RenderTreeType(tree_type) + + if self.request.query_params.get('assets', '0') == '1': + tree_type = RenderTreeType.ASSET + else: + tree_type = RenderTreeType.NODE + + return RenderTreeType(tree_type) + @timeit def list(self, request, *args, **kwargs): - with_assets = request.query_params.get('assets', '0') == '1' - search = request.query_params.get('search') - node_key = request.query_params.get('key') - asset_category = request.query_params.get('category') - asset_type = request.query_params.get('type') - search_node = None - search_asset = None - # test - if search: - search_list = search.split() - for s in search_list: - node = s.split('node:') - if len(node) == 2: - search_node = node[1] - with_assets = False - break + # node / asset + expand_node_key = self.get_query_value('key') + search_node = self.get_query_value('search_node') + search_asset = self.get_query_value('search_asset') + asset_category = self.get_query_value('asset_category') + asset_type = self.get_query_value('asset_type') - asset = s.split('asset:') - if len(asset) == 2: - search_asset = asset[1] - continue - asset_category = s.split('category:') - if len(asset_category) == 2: - asset_category = asset_category[1] - continue - asset_type = s.split('type:') - if len(asset_type) == 2: - asset_type = asset_type[1] - continue - - if node_key: - # 一定是 with_assets - with_assets = True - - if with_assets: - if node_key: - return self.expand_tree_node_with_assets( - node_key, asset_category, asset_type - ) + if self.render_tree_type.is_asset_tree(): + if expand_node_key: + return self.expand_user_perm_asset_tree_node(expand_node_key, asset_category, asset_type) + elif search_node: + # search nodes + return self.search_user_perm_node_tree(search_node, asset_category, asset_type) elif search_asset: # search assets - return self.search_user_perm_tree_with_assets( - search_asset, asset_category, asset_type - ) + return self.search_user_perm_asset_tree(search_asset, asset_category, asset_type) else: - return self.init_user_perm_tree_with_assets( - asset_category, asset_type - ) - else: + return self.init_user_perm_asset_tree(asset_category, asset_type) + else: # if self.render_tree_type.is_node_tree(): + if expand_node_key: + raise NotImplementedError(_('Expanding node in node tree is not supported yet')) if search_node: - # search nodes - return self.search_user_perm_tree(search_node, asset_category, asset_type) + raise NotImplementedError(_('Searching node in node tree is not supported yet')) + if search_asset: + raise NotImplementedError(_('Searching asset in node tree is not supported yet')) else: - return self.init_user_perm_tree(asset_category, asset_type) + return self.init_user_perm_node_tree(asset_category, asset_type) + - def init_user_perm_tree(self, asset_category=None, asset_type=None): + def init_user_perm_node_tree(self, asset_category=None, asset_type=None): ''' 初始化用户权限树 - 不包含资产 前端搜索 @@ -104,20 +128,21 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, nodes = [] for org in orgs: - tree = UserPermTree( + tree = UserPermAssetTree( user=self.user, asset_category=asset_category, asset_type=asset_type, org=org ) _nodes = tree.get_nodes() nodes.extend(_nodes) nodes = self.serialize_nodes( - nodes, with_asset_amount=True, expand_level=expand_level + nodes, with_asset_amount=True, expand_level=expand_level, + tree_type=str(self.render_tree_type) ) data = nodes data = self.add_favorites_and_ungrouped_node(data, with_assets=False) return Response(data=data) - def search_user_perm_tree(self, search, asset_category=None, asset_type=None): + def search_user_perm_node_tree(self, search, asset_category=None, asset_type=None): ''' 搜索用户授权树 - 不包含资产 全局组织: 返回所有匹配节点以及祖先节点,不返回匹配节点的子孙节点,不返回资产,展开所有祖先节点,不展开匹配节点 实体组织: 同上 @@ -130,7 +155,7 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, search_nodes = [] nodes_ancestors = [] for org in orgs: - tree = UserPermTree( + tree = UserPermAssetTree( user=self.user, asset_category=asset_category, asset_type=asset_type, org=org ) @@ -146,7 +171,7 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, with_assets = True serialized_search_nodes = self.serialize_nodes( search_nodes, with_asset_amount=True, expand_level=expand_level, - with_assets=with_assets + tree_type=str(self.render_tree_type) ) # 展开所有祖先节点 expand_level = 10000 @@ -156,7 +181,7 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, data = [*serialized_nodes_ancestors, *serialized_search_nodes] return Response(data=data) - def init_user_perm_tree_with_assets(self, asset_category=None, asset_type=None): + def init_user_perm_asset_tree(self, asset_category=None, asset_type=None): ''' 初始化用户权限资产树 - 包含资产 全局组织: 返回第1级节点,不返回资产,不展开节点 实体组织:返回第1级和第2级节点,返回第1级节点的资产,展开第1级节点 @@ -183,7 +208,7 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, assets = [] for org in orgs: - tree = UserPermTree( + tree = UserPermAssetTree( user=self.user, asset_category=asset_category, asset_type=asset_type, org=org, with_assets_node_levels=with_assets_node_levels @@ -194,14 +219,15 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, assets.extend(_assets) nodes = self.serialize_nodes( - nodes, with_asset_amount=True, expand_level=expand_level, with_assets=True + nodes, with_asset_amount=True, expand_level=expand_level, + tree_type=str(self.render_tree_type) ) assets = self.serialize_assets(assets) data = [*nodes, *assets] data = self.add_favorites_and_ungrouped_node(data, with_assets=True) return Response(data=data) - def expand_tree_node_with_assets(self, node_key, asset_category=None, asset_type=None): + def expand_user_perm_asset_tree_node(self, node_key, asset_category=None, asset_type=None): ''' 展开用户权限资产树节点 - 包含资产 全局组织: 返回展开节点的直接孩子节点,返回展开节点的资产,不展开其他节点 实体组织: 同上 @@ -212,7 +238,7 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, if not org: return Response(data=[]) - tree = UserPermTree( + tree = UserPermAssetTree( user=self.user, asset_category=asset_category, asset_type=asset_type, org=node.org, with_assets_node_id=node.id @@ -223,14 +249,15 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, _nodes = tree_node.children nodes = self.serialize_nodes( - _nodes, with_asset_amount=True, expand_level=expand_level, with_assets=True + _nodes, with_asset_amount=True, expand_level=expand_level, + tree_type=str(self.render_tree_type) ) _assets = tree.get_assets() assets = self.serialize_assets(_assets) data = [*nodes, *assets] return Response(data=data) - def search_user_perm_tree_with_assets(self, search, asset_category=None, asset_type=None): + def search_user_perm_asset_tree(self, search, asset_category=None, asset_type=None): ''' 初始化用户权限资产搜索树 - 包含资产 全局组织: 返回所有节点,返回所有资产,展开所有节点,搜索资产 (最大 1000, n 个组织,每个组织分配1000/n个资产) 实体组织: 同上,最大资产数 1000 @@ -251,7 +278,7 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, nodes = [] assets = [] for org in orgs: - tree = UserPermTree( + tree = UserPermAssetTree( user=self.user, assets_q_object=assets_q_object, org=org, asset_category=asset_category, asset_type=asset_type, with_assets_all=with_assets_all, @@ -263,7 +290,8 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, assets.extend(_assets) nodes = self.serialize_nodes( - nodes, with_asset_amount=True, expand_level=expand_level, with_assets=True + nodes, with_asset_amount=True, expand_level=expand_level, + tree_type=str(self.render_tree_type) ) assets = self.serialize_assets(assets) data = [*nodes, *assets] @@ -286,15 +314,16 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, def get_favorite_node(self, with_assets=False): assets = UserPermUtil.get_favorite_assets(self.user) assets_amount = assets.count() - node = PermTreeNode( - _id=PermTreeNode.SpecialKey.FAVORITE.value, - key=PermTreeNode.SpecialKey.FAVORITE.value, - value=PermTreeNode.SpecialKey.FAVORITE.label, + node = UserPermAssetTreeNode( + _id=UserPermAssetTreeNode.SpecialKey.FAVORITE.value, + key=UserPermAssetTreeNode.SpecialKey.FAVORITE.value, + value=UserPermAssetTreeNode.SpecialKey.FAVORITE.label, assets_amount=assets_amount ) node.assets_amount_total = assets_amount nodes = self.serialize_nodes( - [node], with_asset_amount=True, expand_level=0, with_assets=with_assets + [node], with_asset_amount=True, expand_level=0, + tree_type=str(self.render_tree_type) ) serialized_node = nodes[0] if nodes else None @@ -323,15 +352,16 @@ class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, _util = UserPermUtil(user=self.user, org=org) assets = _util.get_ungrouped_assets() assets_amount = assets.count() - node = PermTreeNode( - _id=PermTreeNode.SpecialKey.UNGROUPED.value, - key=PermTreeNode.SpecialKey.UNGROUPED.value, - value=PermTreeNode.SpecialKey.UNGROUPED.label, + node = UserPermAssetTreeNode( + _id=UserPermAssetTreeNode.SpecialKey.UNGROUPED.value, + key=UserPermAssetTreeNode.SpecialKey.UNGROUPED.value, + value=UserPermAssetTreeNode.SpecialKey.UNGROUPED.label, assets_amount=assets_amount ) node.assets_amount_total = assets_amount nodes = self.serialize_nodes( - [node], with_asset_amount=True, expand_level=0, with_assets=with_assets + [node], with_asset_amount=True, expand_level=0, + tree_type=str(self.render_tree_type) ) serialized_node = nodes[0] if nodes else None diff --git a/apps/perms/tree.py b/apps/perms/tree.py index b5f36cf90..be549af4e 100644 --- a/apps/perms/tree.py +++ b/apps/perms/tree.py @@ -10,13 +10,13 @@ from assets.tree.asset_tree import AssetTree, AssetTreeNode, AssetTreeNodeAsset from perms.utils.utils import UserPermUtil -__all__ = ['UserPermTree'] +__all__ = ['UserPermAssetTree'] logger = get_logger(__name__) -class PermTreeNode(AssetTreeNode): +class UserPermAssetTreeNode(AssetTreeNode): class Type: # Neither a permission node nor a node with direct permission assets @@ -42,9 +42,9 @@ class PermTreeNode(AssetTreeNode): return data -class UserPermTree(AssetTree): +class UserPermAssetTree(AssetTree): - TreeNode = PermTreeNode + TreeNode = UserPermAssetTreeNode def __init__(self, user, **kwargs): @@ -66,11 +66,11 @@ class UserPermTree(AssetTree): def _get_tree_node_data(self, node_id): data = super()._get_tree_node_data(node_id) if node_id in self._util._user_direct_node_all_children_ids: - tp = PermTreeNode.Type.DN + tp = UserPermAssetTreeNode.Type.DN elif self._nodes_assets_amount_mapper.get(node_id, 0) > 0: - tp = PermTreeNode.Type.DA + tp = UserPermAssetTreeNode.Type.DA else: - tp = PermTreeNode.Type.BRIDGE + tp = UserPermAssetTreeNode.Type.BRIDGE data.update({ 'tp': tp }) return data