perf: 授权类型树 (#10390)

Co-authored-by: feng <1304903146@qq.com>
pull/10432/head
fit2bot 2023-05-11 10:15:40 +08:00 committed by GitHub
parent b98aa377b6
commit f06059837d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 125 additions and 19 deletions

View File

@ -69,7 +69,7 @@ class SerializeToTreeNodeMixin:
return 'file' return 'file'
@timeit @timeit
def serialize_assets(self, assets, node_key=None): def serialize_assets(self, assets, node_key=None, pid=None):
sftp_enabled_platform = PlatformProtocol.objects \ sftp_enabled_platform = PlatformProtocol.objects \
.filter(name='ssh', setting__sftp_enabled=True) \ .filter(name='ssh', setting__sftp_enabled=True) \
.values_list('platform', flat=True) \ .values_list('platform', flat=True) \
@ -83,8 +83,10 @@ class SerializeToTreeNodeMixin:
{ {
'id': str(asset.id), 'id': str(asset.id),
'name': asset.name, 'name': asset.name,
'title': f'{asset.address}\n{asset.comment}', 'title':
'pId': get_pid(asset), f'{asset.address}\n{asset.comment}'
if asset.comment else asset.address,
'pId': pid or get_pid(asset),
'isParent': False, 'isParent': False,
'open': False, 'open': False,
'iconSkin': self.get_icon(asset), 'iconSkin': self.get_icon(asset),

View File

@ -193,15 +193,38 @@ class AllTypes(ChoicesMixin):
} }
return node return node
@classmethod
def to_tree_nodes(cls, include_asset, count_resource='asset'):
from accounts.models import Account
from ..models import Asset, Platform
if count_resource == 'account':
resource_platforms = Account.objects.all().values_list('asset__platform_id', flat=True)
else:
resource_platforms = Asset.objects.all().values_list('platform_id', flat=True)
@classmethod
def asset_to_node(cls, asset, pid):
node = {
'id': '{}'.format(asset.id),
'name': asset.name,
'title': f'{asset.address}\n{asset.comment}',
'pId': pid,
'isParent': False,
'open': False,
'iconSkin': asset.type,
'chkDisabled': not asset.is_active,
'meta': {
'type': 'platform',
'data': {
'platform_type': asset.platform.type,
'org_name': asset.org_name,
# 'sftp': asset.platform_id in sftp_enabled_platform,
'name': asset.name,
'address': asset.address
},
}
}
return node
@classmethod
def get_root_nodes(cls):
return dict(id='ROOT', name=_('All types'), title=_('All types'), open=True, isParent=True)
@classmethod
def get_tree_nodes(cls, resource_platforms, include_asset=False):
from ..models import Platform
platform_count = defaultdict(int) platform_count = defaultdict(int)
for platform_id in resource_platforms: for platform_id in resource_platforms:
platform_count[platform_id] += 1 platform_count[platform_id] += 1
@ -215,8 +238,7 @@ class AllTypes(ChoicesMixin):
category_type_mapper[p.category] += platform_count[p.id] category_type_mapper[p.category] += platform_count[p.id]
tp_platforms[p.category + '_' + p.type].append(p) tp_platforms[p.category + '_' + p.type].append(p)
root = dict(id='ROOT', name=_('All types'), title=_('All types'), open=True, isParent=True) nodes = [cls.get_root_nodes()]
nodes = [root]
for category, type_cls in cls.category_types(): for category, type_cls in cls.category_types():
# Category 格式化 # Category 格式化
meta = {'type': 'category', 'category': category.value} meta = {'type': 'category', 'category': category.value}
@ -244,6 +266,16 @@ class AllTypes(ChoicesMixin):
nodes.append(platform_node) nodes.append(platform_node)
return nodes return nodes
@classmethod
def to_tree_nodes(cls, include_asset, count_resource='asset'):
from accounts.models import Account
from ..models import Asset
if count_resource == 'account':
resource_platforms = Account.objects.all().values_list('asset__platform_id', flat=True)
else:
resource_platforms = Asset.objects.all().values_list('platform_id', flat=True)
return cls.get_tree_nodes(resource_platforms, include_asset)
@classmethod @classmethod
def get_type_default_platform(cls, category, tp): def get_type_default_platform(cls, category, tp):
constraints = cls.get_constraints(category, tp) constraints = cls.get_constraints(category, tp)

View File

@ -1,4 +1,6 @@
import abc import abc
import re
from collections import defaultdict
from urllib.parse import parse_qsl from urllib.parse import parse_qsl
from django.conf import settings from django.conf import settings
@ -11,6 +13,7 @@ from rest_framework.response import Response
from accounts.const import AliasAccount from accounts.const import AliasAccount
from assets.api import SerializeToTreeNodeMixin from assets.api import SerializeToTreeNodeMixin
from assets.const import AllTypes
from assets.models import Asset from assets.models import Asset
from assets.utils import KubernetesTree from assets.utils import KubernetesTree
from authentication.models import ConnectionToken from authentication.models import ConnectionToken
@ -26,7 +29,8 @@ from ..mixin import SelfOrPKUserMixin
__all__ = [ __all__ = [
'UserGrantedK8sAsTreeApi', 'UserGrantedK8sAsTreeApi',
'UserPermedNodesWithAssetsAsTreeApi', 'UserPermedNodesWithAssetsAsTreeApi',
'UserPermedNodeChildrenWithAssetsAsTreeApi' 'UserPermedNodeChildrenWithAssetsAsTreeApi',
'UserPermedNodeChildrenWithAssetsAsCategoryTreeApi',
] ]
@ -137,6 +141,75 @@ class UserPermedNodeChildrenWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
return self.query_node_key or self.default_unfolded_node_key return self.query_node_key or self.default_unfolded_node_key
class UserPermedNodeChildrenWithAssetsAsCategoryTreeApi(
SelfOrPKUserMixin, SerializeToTreeNodeMixin, ListAPIView
):
@property
def is_sync(self):
sync = self.request.query_params.get('sync', 0)
return int(sync) == 1
@property
def tp(self):
return self.request.query_params.get('type')
def get_assets(self):
query_asset_util = UserPermAssetUtil(self.user)
node = PermNode.objects.filter(
granted_node_rels__user=self.user, parent_key='').first()
if node:
__, assets = query_asset_util.get_node_all_assets(node.id)
else:
assets = Asset.objects.none()
return assets
def to_tree_nodes(self, assets):
if not assets:
return []
assets = assets.annotate(tp=F('platform__type'))
asset_type_map = defaultdict(list)
for asset in assets:
asset_type_map[asset.tp].append(asset)
tp = self.tp
if tp:
assets = asset_type_map.get(tp, [])
if not assets:
return []
pid = f'ROOT_{str(assets[0].category).upper()}_{tp}'
return self.serialize_assets(assets, pid=pid)
resource_platforms = assets.values_list('platform_id', flat=True)
node_all = AllTypes.get_tree_nodes(resource_platforms)
pattern = re.compile(r'\(0\)?')
nodes = []
for node in node_all:
meta = node.get('meta', {})
if pattern.search(node['name']) or meta.get('type') == 'platform':
continue
_type = meta.get('_type')
if _type:
node['type'] = _type
nodes.append(node)
if not self.is_sync:
return nodes
asset_nodes = []
for node in nodes:
node['open'] = True
tp = node.get('meta', {}).get('_type')
if not tp:
continue
assets = asset_type_map.get(tp, [])
asset_nodes += self.serialize_assets(assets, pid=node['id'])
return nodes + asset_nodes
def list(self, request, *args, **kwargs):
assets = self.get_assets()
nodes = self.to_tree_nodes(assets)
return Response(data=nodes)
class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView): class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView):
""" 用户授权的K8s树 """ """ 用户授权的K8s树 """

View File

@ -37,6 +37,9 @@ user_permission_urlpatterns = [
path('<str:user>/nodes/children-with-assets/tree/', path('<str:user>/nodes/children-with-assets/tree/',
api.UserPermedNodeChildrenWithAssetsAsTreeApi.as_view(), api.UserPermedNodeChildrenWithAssetsAsTreeApi.as_view(),
name='user-node-children-with-assets-as-tree'), 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/', path('<str:user>/nodes/all-with-assets/tree/',
api.UserPermedNodesWithAssetsAsTreeApi.as_view(), api.UserPermedNodesWithAssetsAsTreeApi.as_view(),

View File

@ -1,15 +1,11 @@
from assets.models import FavoriteAsset, Asset
from django.conf import settings from django.conf import settings
from django.db.models import Q from django.db.models import Q
from assets.models import FavoriteAsset, Asset
from common.utils.common import timeit from common.utils.common import timeit
from perms.models import AssetPermission, PermNode, UserAssetGrantedTreeNodeRelation from perms.models import AssetPermission, PermNode, UserAssetGrantedTreeNodeRelation
from .permission import AssetPermissionUtil from .permission import AssetPermissionUtil
__all__ = ['AssetPermissionPermAssetUtil', 'UserPermAssetUtil', 'UserPermNodeUtil'] __all__ = ['AssetPermissionPermAssetUtil', 'UserPermAssetUtil', 'UserPermNodeUtil']