mirror of
https://github.com/jumpserver/jumpserver.git
synced 2026-03-18 19:12:07 +00:00
refactor: UserPermTreeAPI finished - Luna Page
This commit is contained in:
@@ -146,7 +146,7 @@ class NodeChildrenAsTreeApi(SerializeToTreeNodeMixin, NodeChildrenApi):
|
||||
if current_org.is_root():
|
||||
orgs = Organization.objects.all()
|
||||
node_levels = [1]
|
||||
with_assets_node_levels = []
|
||||
with_assets_node_levels = None
|
||||
expand_level = 0
|
||||
else:
|
||||
orgs = [current_org]
|
||||
@@ -211,7 +211,7 @@ class NodeChildrenAsTreeApi(SerializeToTreeNodeMixin, NodeChildrenApi):
|
||||
assets_q_object = Q(name__icontains=search) | Q(address__icontains=search)
|
||||
if current_org.is_root():
|
||||
orgs = list(Organization.objects.all())
|
||||
with_assets_limit = with_assets_limit / len(orgs)
|
||||
with_assets_limit = max(100, with_assets_limit // max(1, orgs.count()))
|
||||
else:
|
||||
orgs = [current_org]
|
||||
|
||||
|
||||
128
apps/perms/api/user_permission/tree.py
Normal file
128
apps/perms/api/user_permission/tree.py
Normal file
@@ -0,0 +1,128 @@
|
||||
from django.db.models import Q
|
||||
|
||||
from rest_framework.generics import ListAPIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.generics import get_object_or_404
|
||||
|
||||
from common.utils import get_logger, timeit
|
||||
from orgs.utils import current_org
|
||||
from assets.api import SerializeToTreeNodeMixin
|
||||
from assets.models import Node
|
||||
from perms.tree import UserPermTree, PermTreeNode
|
||||
|
||||
from .mixin import SelfOrPKUserMixin
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
__all__ = [
|
||||
'UserPermNodeChildrenAsTreeApi'
|
||||
]
|
||||
|
||||
|
||||
class UserPermNodeChildrenAsTreeApi(SelfOrPKUserMixin, SerializeToTreeNodeMixin, ListAPIView):
|
||||
|
||||
@timeit
|
||||
def list(self, request, *args, **kwargs):
|
||||
search = request.query_params.get('search')
|
||||
key = request.query_params.get('key')
|
||||
if search:
|
||||
return self.search_user_perm_tree_with_assets(search)
|
||||
|
||||
if key:
|
||||
return self.expand_tree_node_with_assets(key)
|
||||
|
||||
return self.init_user_perm_tree_with_assets()
|
||||
|
||||
def init_user_perm_tree_with_assets(self):
|
||||
''' 初始化用户权限资产树 - 包含资产
|
||||
全局组织: 返回第1级节点,不返回资产,不展开节点
|
||||
实体组织:返回第1级和第2级节点,返回第1级节点的资产,展开第1级节点
|
||||
|
||||
返回收藏节点和资产
|
||||
返回未分组节点和资产 (如果需要)
|
||||
'''
|
||||
if current_org.is_root():
|
||||
orgs = self.user.orgs.all()
|
||||
nodes_level = [1]
|
||||
with_assets_node_levels = None
|
||||
expand_level = 0
|
||||
else:
|
||||
orgs = [current_org]
|
||||
nodes_level = [1, 2]
|
||||
with_assets_node_levels = [1]
|
||||
expand_level = 1
|
||||
|
||||
nodes = []
|
||||
assets = []
|
||||
for org in orgs:
|
||||
tree = UserPermTree(
|
||||
user=self.user, org=org, with_assets_node_levels=with_assets_node_levels
|
||||
)
|
||||
_nodes = tree.get_nodes(levels=nodes_level)
|
||||
nodes.extend(_nodes)
|
||||
_assets = tree.get_assets()
|
||||
assets.extend(_assets)
|
||||
|
||||
nodes = self.serialize_nodes(
|
||||
nodes, with_asset_amount=True, expand_level=expand_level, with_assets=True
|
||||
)
|
||||
assets = self.serialize_assets(assets)
|
||||
data = [*nodes, *assets]
|
||||
return Response(data)
|
||||
|
||||
def expand_tree_node_with_assets(self, key):
|
||||
''' 展开用户权限资产树节点 - 包含资产
|
||||
全局组织: 返回展开节点的直接孩子节点,返回展开节点的资产,不展开其他节点
|
||||
实体组织: 同上
|
||||
'''
|
||||
expand_level = 0
|
||||
node = get_object_or_404(Node, key=key)
|
||||
tree = UserPermTree(
|
||||
user=self.user, org=node.org, with_assets_node_id=node.id
|
||||
)
|
||||
tree_node = tree.get_node(node.key)
|
||||
if not tree_node:
|
||||
return Response(data=[])
|
||||
|
||||
_nodes = tree_node.children
|
||||
nodes = self.serialize_nodes(
|
||||
_nodes, with_asset_amount=True, expand_level=expand_level, with_assets=True
|
||||
)
|
||||
_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):
|
||||
''' 初始化用户权限资产搜索树 - 包含资产
|
||||
全局组织: 返回所有节点,返回所有资产,展开所有节点,搜索资产 (最大 1000, n 个组织,每个组织分配1000/n个资产)
|
||||
实体组织: 同上,最大资产数 1000
|
||||
'''
|
||||
expand_level = 10000
|
||||
with_assets_all = True
|
||||
with_assets_limit = 1000
|
||||
if current_org.is_root():
|
||||
orgs = self.user.orgs.all()
|
||||
with_assets_limit = max(100, with_assets_limit // max(1, orgs.count()))
|
||||
else:
|
||||
orgs = [current_org]
|
||||
assets_q_object = Q(name__icontains=search) | Q(address__icontains=search)
|
||||
nodes = []
|
||||
assets = []
|
||||
for org in orgs:
|
||||
tree = UserPermTree(
|
||||
user=self.user, assets_q_object=assets_q_object, org=org,
|
||||
with_assets_all=with_assets_all,
|
||||
with_assets_limit=with_assets_limit
|
||||
)
|
||||
_nodes = tree.get_nodes()
|
||||
nodes.extend(_nodes)
|
||||
_assets = tree.get_assets()
|
||||
assets.extend(_assets)
|
||||
|
||||
nodes = self.serialize_nodes(
|
||||
nodes, with_asset_amount=True, expand_level=expand_level, with_assets=True
|
||||
)
|
||||
assets = self.serialize_assets(assets)
|
||||
data = [*nodes, *assets]
|
||||
return Response(data=data)
|
||||
@@ -1,9 +1,12 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from collections import defaultdict
|
||||
from django.db.models import Q, Count
|
||||
from django.db.models import Q, Count, TextChoices
|
||||
from django.core.cache import cache
|
||||
|
||||
from common.utils import get_logger
|
||||
from users.models import User
|
||||
from assets.tree.asset_tree import AssetTree, AssetTreeNode
|
||||
from assets.models import FavoriteAsset, Asset
|
||||
from assets.tree.asset_tree import AssetTree, AssetTreeNode, AssetTreeNodeAsset
|
||||
from perms.utils.utils import UserPermUtil
|
||||
|
||||
|
||||
@@ -23,9 +26,9 @@ class PermTreeNode(AssetTreeNode):
|
||||
# Node with only direct permission assets
|
||||
DA = 'da'
|
||||
|
||||
def __init__(self, tp, _id, key, value, assets_count=0, assets=None):
|
||||
super().__init__(_id, key, value, assets_count)
|
||||
def __init__(self, tp=None, **kwargs):
|
||||
self.type = tp or self.Type.BRIDGE
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def as_dict(self, simple=True):
|
||||
data = super().as_dict(simple=simple)
|
||||
@@ -33,27 +36,26 @@ class PermTreeNode(AssetTreeNode):
|
||||
'type': self.type,
|
||||
})
|
||||
return data
|
||||
|
||||
|
||||
|
||||
class UserPermTree(AssetTree):
|
||||
|
||||
TreeNode = PermTreeNode
|
||||
|
||||
def __init__(self, user=None, assets_q_object=None, category=None, org=None, with_assets=False):
|
||||
super().__init__(
|
||||
assets_q_object=assets_q_object,
|
||||
category=category,
|
||||
org=org,
|
||||
with_assets=with_assets,
|
||||
full_tree=False
|
||||
)
|
||||
def __init__(self, user, **kwargs):
|
||||
|
||||
self._user: User = user
|
||||
self._util = UserPermUtil(user, org=self._org)
|
||||
|
||||
self._util = UserPermUtil(user, org=kwargs.get('org'))
|
||||
kwargs.update({
|
||||
# 用户授权树只返回有资产的节点
|
||||
'full_tree': False,
|
||||
})
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def _make_assets_q_object(self):
|
||||
q = super()._make_assets_q_object()
|
||||
q_perm_assets = Q(id__in=self._util._user_direct_asset_ids)
|
||||
q_perm_nodes = Q(node_id__in=self._util._user_direct_node_all_children_ids)
|
||||
q_perm_assets = Q(id__in=list(self._util._user_direct_asset_ids))
|
||||
q_perm_nodes = Q(node_id__in=list(self._util._user_direct_node_all_children_ids))
|
||||
q = q & (q_perm_assets | q_perm_nodes)
|
||||
return q
|
||||
|
||||
@@ -61,13 +63,13 @@ class UserPermTree(AssetTree):
|
||||
data = super()._get_tree_node_data(node_id)
|
||||
if node_id in self._util._user_direct_node_all_children_ids:
|
||||
tp = PermTreeNode.Type.DN
|
||||
elif self._nodes_assets_count_mapper.get(node_id, 0) > 0:
|
||||
elif self._nodes_assets_amount_mapper.get(node_id, 0) > 0:
|
||||
tp = PermTreeNode.Type.DA
|
||||
else:
|
||||
tp = PermTreeNode.Type.BRIDGE
|
||||
data.update({ 'tp': tp })
|
||||
return data
|
||||
|
||||
|
||||
def print(self, simple=True, count=10):
|
||||
self._util.print()
|
||||
super().print(simple=simple, count=count)
|
||||
|
||||
@@ -23,30 +23,34 @@ user_permission_urlpatterns = [
|
||||
path('<str:user>/nodes/children/', api.UserPermedNodeChildrenApi.as_view(),
|
||||
name='user-node-children'),
|
||||
|
||||
# 授权树只通过这一个 API 获取, 类似资产树
|
||||
path('<str:user>/nodes/children/tree/', api.UserPermNodeChildrenAsTreeApi.as_view(),
|
||||
name='user-perm-node-children-tree'),
|
||||
|
||||
# tree-asset
|
||||
path('<str:user>/assets/tree/', api.UserAllPermedAssetsAsTreeApi.as_view(),
|
||||
name='user-direct-assets-as-tree'),
|
||||
path('<str:user>/ungroup/assets/tree/', api.UserUngroupAssetsAsTreeApi.as_view(),
|
||||
name='user-ungroup-assets-as-tree'),
|
||||
# path('<str:user>/assets/tree/', api.UserAllPermedAssetsAsTreeApi.as_view(),
|
||||
# name='user-direct-assets-as-tree'),
|
||||
# path('<str:user>/ungroup/assets/tree/', api.UserUngroupAssetsAsTreeApi.as_view(),
|
||||
# name='user-ungroup-assets-as-tree'),
|
||||
|
||||
# tree-node,不包含资产
|
||||
path('<str:user>/nodes/tree/', api.UserAllPermedNodesAsTreeApi.as_view(),
|
||||
name='user-all-nodes-as-tree'),
|
||||
path('<str:user>/nodes/children/tree/', api.UserPermedNodeChildrenAsTreeApi.as_view(),
|
||||
name='user-node-children-as-tree'),
|
||||
# path('<str:user>/nodes/tree/', api.UserAllPermedNodesAsTreeApi.as_view(),
|
||||
# name='user-all-nodes-as-tree'),
|
||||
# path('<str:user>/nodes/children/tree/', api.UserPermedNodeChildrenAsTreeApi.as_view(),
|
||||
# name='user-node-children-as-tree'),
|
||||
|
||||
# tree-node-with-asset
|
||||
# 异步树
|
||||
path('<str:user>/nodes/children-with-assets/tree/',
|
||||
api.UserPermedNodeChildrenWithAssetsAsTreeApi.as_view(),
|
||||
name='user-node-children-with-assets-as-tree'),
|
||||
path('<str:user>/nodes/children-with-assets/category/tree/',
|
||||
api.UserPermedNodeChildrenWithAssetsAsCategoryTreeApi.as_view(),
|
||||
name='user-node-children-with-assets-as-category-tree'),
|
||||
# path('<str:user>/nodes/children-with-assets/tree/',
|
||||
# api.UserPermedNodeChildrenWithAssetsAsTreeApi.as_view(),
|
||||
# name='user-node-children-with-assets-as-tree'),
|
||||
# path('<str:user>/nodes/children-with-assets/category/tree/',
|
||||
# api.UserPermedNodeChildrenWithAssetsAsCategoryTreeApi.as_view(),
|
||||
# name='user-node-children-with-assets-as-category-tree'),
|
||||
# 同步树
|
||||
path('<str:user>/nodes/all-with-assets/tree/',
|
||||
api.UserPermedNodesWithAssetsAsTreeApi.as_view(),
|
||||
name='user-nodes-with-assets-as-tree'),
|
||||
# path('<str:user>/nodes/all-with-assets/tree/',
|
||||
# api.UserPermedNodesWithAssetsAsTreeApi.as_view(),
|
||||
# name='user-nodes-with-assets-as-tree'),
|
||||
]
|
||||
|
||||
user_group_permission_urlpatterns = [
|
||||
|
||||
@@ -34,6 +34,7 @@ class UserPermUtil(object):
|
||||
self._user_direct_node_all_children_ids = set()
|
||||
self._init()
|
||||
|
||||
@timeit
|
||||
def _init(self):
|
||||
self._load_user_permission_ids()
|
||||
self._load_user_group_ids()
|
||||
@@ -45,7 +46,8 @@ class UserPermUtil(object):
|
||||
@timeit
|
||||
def _load_user_permission_ids(self):
|
||||
perm_ids = self.PermUserThrough.objects.filter(
|
||||
user_id=self._user.id
|
||||
user_id=self._user.id,
|
||||
assetpermission__org_id=self._org.id
|
||||
).distinct('assetpermission_id').values_list('assetpermission_id', flat=True)
|
||||
perm_ids = self._uuids_to_string(perm_ids)
|
||||
self._user_permission_ids.update(perm_ids)
|
||||
@@ -54,7 +56,8 @@ class UserPermUtil(object):
|
||||
@timeit
|
||||
def _load_user_group_ids(self):
|
||||
group_ids = self.UserGroupThrough.objects.filter(
|
||||
user_id=self._user.id
|
||||
user_id=self._user.id,
|
||||
usergroup__org_id=self._org.id
|
||||
).distinct('usergroup_id').values_list('usergroup_id', flat=True)
|
||||
group_ids = self._uuids_to_string(group_ids)
|
||||
self._user_group_ids.update(group_ids)
|
||||
@@ -62,7 +65,8 @@ class UserPermUtil(object):
|
||||
@timeit
|
||||
def _load_user_group_permission_ids(self):
|
||||
perm_ids = self.PermUserGroupThrough.objects.filter(
|
||||
usergroup_id__in=self._user_group_ids
|
||||
usergroup_id__in=self._user_group_ids,
|
||||
assetpermission__org_id=self._org.id
|
||||
).distinct('assetpermission_id').values_list('assetpermission_id', flat=True)
|
||||
perm_ids = self._uuids_to_string(perm_ids)
|
||||
self._user_group_permission_ids.update(perm_ids)
|
||||
@@ -89,27 +93,35 @@ class UserPermUtil(object):
|
||||
nid_key_pairs = Node.objects.filter(org_id=self._org.id).values_list('id', 'key')
|
||||
nid_key_mapper = { str(nid): key for nid, key in nid_key_pairs }
|
||||
|
||||
dn_keys = [ nid_key_mapper[nid] for nid in self._user_direct_node_ids ]
|
||||
dn_keys = [
|
||||
nid_key_mapper[nid] for nid in self._user_direct_node_ids
|
||||
]
|
||||
|
||||
def has_ancestor_in_direct_nodes(key: str) -> bool:
|
||||
ancestor_keys = [ ':'.join(key.split(':')[:i]) for i in range(1, key.count(':') + 1) ]
|
||||
ancestor_keys = [
|
||||
':'.join(key.split(':')[:i])
|
||||
for i in range(1, key.count(':') + 1)
|
||||
]
|
||||
return bool(set(ancestor_keys) & set(dn_keys))
|
||||
|
||||
dn_children_ids = [ nid for nid, key in nid_key_mapper.items() if has_ancestor_in_direct_nodes(key) ]
|
||||
dn_children_ids = [
|
||||
nid for nid, key in nid_key_mapper.items()
|
||||
if has_ancestor_in_direct_nodes(key)
|
||||
]
|
||||
|
||||
self._user_direct_node_all_children_ids.update(self._user_direct_node_ids)
|
||||
self._user_direct_node_all_children_ids.update(dn_children_ids)
|
||||
|
||||
def get_node_assets(self, node: Node):
|
||||
''' 获取节点下授权的直接资产, Luna 页面展开时需要 '''
|
||||
''' 获取节点下授权的直接资产 '''
|
||||
q = Q(node_id=node.id)
|
||||
if str(node.id) not in self._user_direct_node_all_children_ids:
|
||||
q &= Q(id__in=self._user_direct_asset_ids)
|
||||
assets = Asset.objects.filter(q)
|
||||
assets = Asset.objects.filter(org_id=self._org.id).filter(q)
|
||||
return assets
|
||||
|
||||
def get_node_all_assets(self, node: Node):
|
||||
''' 获取节点及其子节点下所有授权资产, 测试时需要 '''
|
||||
''' 获取节点及其子节点下所有授权资产 '''
|
||||
if str(node.id) in self._user_direct_node_all_children_ids:
|
||||
assets = node.get_all_assets()
|
||||
return assets
|
||||
@@ -121,7 +133,7 @@ class UserPermUtil(object):
|
||||
|
||||
q = Q(node_id__in=dn_all_nodes_ids)
|
||||
q |= Q(node_id__in=other_nodes_ids) & Q(id__in=self._user_direct_asset_ids)
|
||||
assets = Asset.objects.filter(q)
|
||||
assets = Asset.objects.filter(org_id=self._org.id).filter(q)
|
||||
return assets
|
||||
|
||||
def _uuids_to_string(self, uuids):
|
||||
|
||||
Reference in New Issue
Block a user