Merge branch 'v3' of github.com:jumpserver/jumpserver into v3

pull/9169/head
ibuler 2022-12-07 18:59:28 +08:00
commit a27b43107c
17 changed files with 339 additions and 428 deletions

View File

@ -30,16 +30,13 @@ __all__ = [
class AssetFilterSet(BaseFilterSet):
type = django_filters.CharFilter(field_name="platform__type", lookup_expr="exact")
category = django_filters.CharFilter(
field_name="platform__category", lookup_expr="exact"
)
hostname = django_filters.CharFilter(field_name="name", lookup_expr="exact")
category = django_filters.CharFilter(field_name="platform__category", lookup_expr="exact")
class Meta:
model = Asset
fields = [
"id", "name", "address", "is_active",
"type", "category", "hostname"
"type", "category"
]

View File

@ -23,8 +23,8 @@ __all__ = [
class UserGroupGrantedAssetsApi(ListAPIView):
serializer_class = serializers.AssetGrantedSerializer
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
serializer_class = serializers.AssetPermedSerializer
only_fields = serializers.AssetPermedSerializer.Meta.only_fields
filterset_fields = ['name', 'address', 'id', 'comment']
search_fields = ['name', 'address', 'comment']
rbac_perms = {
@ -60,8 +60,8 @@ class UserGroupGrantedAssetsApi(ListAPIView):
class UserGroupGrantedNodeAssetsApi(ListAPIView):
serializer_class = serializers.AssetGrantedSerializer
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
serializer_class = serializers.AssetPermedSerializer
only_fields = serializers.AssetPermedSerializer.Meta.only_fields
filterset_fields = ['name', 'address', 'id', 'comment']
search_fields = ['name', 'address', 'comment']
rbac_perms = {

View File

@ -2,5 +2,5 @@
#
from .nodes import *
from .assets import *
from .nodes_with_assets import *
from .accounts import *
from .tree import *

View File

@ -25,6 +25,5 @@ class UserPermedAssetAccountsApi(SelfOrPKUserMixin, ListAPIView):
return asset
def get_queryset(self):
util = PermAccountUtil()
accounts = util.get_permed_accounts_for_user(self.user, self.asset)
accounts = PermAccountUtil().get_permed_accounts_for_user(self.user, self.asset)
return accounts

View File

@ -1,109 +1,76 @@
from django.conf import settings
import abc
from rest_framework.generics import ListAPIView
from assets.models import Asset, Node
from common.utils import get_logger
from assets.api.asset.asset import AssetFilterSet
from perms import serializers
from perms.pagination import AllGrantedAssetPagination
from perms.pagination import NodeGrantedAssetPagination
from perms.pagination import AllPermedAssetPagination
from perms.pagination import NodePermedAssetPagination
from perms.utils.user_permission import UserGrantedAssetsQueryUtils
from common.utils import get_logger, lazyproperty
from .mixin import (
SelfOrPKUserMixin, RebuildTreeMixin,
PermedAssetSerializerMixin, AssetsTreeFormatMixin
SelfOrPKUserMixin
)
__all__ = [
'UserAllPermedAssetsApi',
'UserDirectPermedAssetsApi',
'UserFavoriteAssetsApi',
'UserDirectPermedAssetsAsTreeApi',
'UserUngroupAssetsAsTreeApi',
'UserAllPermedAssetsApi',
'UserPermedNodeAssetsApi',
]
logger = get_logger(__name__)
class UserDirectPermedAssetsApi(SelfOrPKUserMixin, PermedAssetSerializerMixin, ListAPIView):
""" 直接授权给用户的资产 """
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
class BaseUserPermedAssetsApi(SelfOrPKUserMixin, ListAPIView):
ordering = ('name',)
ordering_fields = ("name", "address")
search_fields = ('name', 'address', 'comment')
filterset_class = AssetFilterSet
serializer_class = serializers.AssetPermedSerializer
only_fields = serializers.AssetPermedSerializer.Meta.only_fields
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Asset.objects.none()
assets = UserGrantedAssetsQueryUtils(self.user) \
.get_direct_granted_assets() \
.prefetch_related('platform') \
.only(*self.only_fields)
return assets
class UserFavoriteAssetsApi(SelfOrPKUserMixin, PermedAssetSerializerMixin, ListAPIView):
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
""" 用户收藏的授权资产 """
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Asset.objects.none()
user = self.user
utils = UserGrantedAssetsQueryUtils(user)
assets = utils.get_favorite_assets()
assets = self.get_assets()
assets = assets.prefetch_related('platform').only(*self.only_fields)
return assets
@abc.abstractmethod
def get_assets(self):
return Asset.objects.none()
class UserDirectPermedAssetsAsTreeApi(RebuildTreeMixin, AssetsTreeFormatMixin, UserDirectPermedAssetsApi):
""" 用户直接授权的资产作为树 """
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Asset.objects.none()
assets = UserGrantedAssetsQueryUtils(self.user) \
.get_direct_granted_assets() \
.prefetch_related('platform') \
.only(*self.only_fields)
return assets
@lazyproperty
def query_asset_util(self):
return UserGrantedAssetsQueryUtils(self.user)
class UserUngroupAssetsAsTreeApi(UserDirectPermedAssetsAsTreeApi):
""" 用户未分组节点下的资产作为树 """
class UserAllPermedAssetsApi(BaseUserPermedAssetsApi):
pagination_class = AllPermedAssetPagination
def get_queryset(self):
queryset = super().get_queryset()
if not settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
queryset = queryset.none()
return queryset
def get_assets(self):
return self.query_asset_util.get_all_granted_assets()
class UserAllPermedAssetsApi(SelfOrPKUserMixin, PermedAssetSerializerMixin, ListAPIView):
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
pagination_class = AllGrantedAssetPagination
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Asset.objects.none()
queryset = UserGrantedAssetsQueryUtils(self.user).get_all_granted_assets()
only_fields = [i for i in self.only_fields if i not in ['protocols']]
queryset = queryset.prefetch_related('platform', 'protocols').only(*only_fields)
return queryset
class UserDirectPermedAssetsApi(BaseUserPermedAssetsApi):
def get_assets(self):
return self.query_asset_util.get_direct_granted_assets()
class UserPermedNodeAssetsApi(SelfOrPKUserMixin, PermedAssetSerializerMixin, ListAPIView):
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
pagination_class = NodeGrantedAssetPagination
kwargs: dict
class UserFavoriteAssetsApi(BaseUserPermedAssetsApi):
def get_assets(self):
return self.query_asset_util.get_favorite_assets()
class UserPermedNodeAssetsApi(BaseUserPermedAssetsApi):
pagination_class = NodePermedAssetPagination
pagination_node: Node
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Asset.objects.none()
def get_assets(self):
node_id = self.kwargs.get("node_id")
node, assets = UserGrantedAssetsQueryUtils(self.user).get_node_all_assets(node_id)
assets = assets.prefetch_related('platform').only(*self.only_fields)
node, assets = self.query_asset_util.get_node_all_assets(node_id)
self.pagination_node = node
return assets

View File

@ -3,27 +3,13 @@
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
from rest_framework.request import Request
from rest_framework.response import Response
from assets.api.asset.asset import AssetFilterSet
from assets.api.mixin import SerializeToTreeNodeMixin
from common.exceptions import JMSObjectDoesNotExist
from common.http import is_true
from common.utils import is_uuid
from perms import serializers
from perms.utils.user_permission import UserGrantedTreeRefreshController
from rbac.permissions import RBACPermission
from users.models import User
from rbac.permissions import RBACPermission
from common.utils import is_uuid
from common.exceptions import JMSObjectDoesNotExist
class RebuildTreeMixin:
user: User
def get(self, request: Request, *args, **kwargs):
force = is_true(request.query_params.get('rebuild_tree'))
controller = UserGrantedTreeRefreshController(self.user)
controller.refresh_if_need(force)
return super().get(request, *args, **kwargs)
__all__ = ['SelfOrPKUserMixin']
class SelfOrPKUserMixin:
@ -72,32 +58,3 @@ class SelfOrPKUserMixin:
def request_user_is_self(self):
return self.kwargs.get('user') in ['my', 'self']
class PermedAssetSerializerMixin:
serializer_class = serializers.AssetGrantedSerializer
filterset_class = AssetFilterSet
search_fields = ['name', 'address', 'comment']
ordering_fields = ("name", "address")
ordering = ('name',)
class AssetsTreeFormatMixin(SerializeToTreeNodeMixin):
"""
资产 序列化成树的结构返回
"""
filter_queryset: callable
get_queryset: callable
filterset_fields = ['name', 'address', 'id', 'comment']
search_fields = ['name', 'address', 'comment']
def list(self, request: Request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
if request.query_params.get('search'):
# 如果用户搜索的条件不精准,会导致返回大量的无意义数据。
# 这里限制一下返回数据的最大条数
queryset = queryset[:999]
queryset = sorted(queryset, key=lambda asset: asset.name)
data = self.serialize_assets(queryset, None)
return Response(data=data)

View File

@ -1,133 +1,49 @@
# -*- coding: utf-8 -*-
#
import abc
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.generics import ListAPIView
from common.utils import get_logger
from assets.api.mixin import SerializeToTreeNodeMixin
from assets.models import Node
from perms import serializers
from perms.hands import User
from perms.utils.user_permission import UserGrantedNodesQueryUtils
from common.utils import get_logger, lazyproperty
from .mixin import SelfOrPKUserMixin, RebuildTreeMixin
from .mixin import SelfOrPKUserMixin
logger = get_logger(__name__)
__all__ = [
'UserPermedNodesApi',
'UserPermedNodesAsTreeApi',
'UserAllPermedNodesApi',
'UserPermedNodeChildrenApi',
'UserPermedNodeChildrenAsTreeApi',
'BaseGrantedNodeAsTreeApi',
'UserGrantedNodesMixin',
]
class _GrantedNodeStructApi(ListAPIView, metaclass=abc.ABCMeta):
@property
def user(self):
raise NotImplementedError
def get_nodes(self):
# 不使用 `get_queryset` 单独定义 `get_nodes` 的原因是
# `get_nodes` 返回的不一定是 `queryset`
raise NotImplementedError
class NodeChildrenMixin:
def get_children(self):
raise NotImplementedError
def get_nodes(self):
nodes = self.get_children()
return nodes
class BaseGrantedNodeApi(_GrantedNodeStructApi, metaclass=abc.ABCMeta):
class BaseUserPermedNodesApi(SelfOrPKUserMixin, ListAPIView):
serializer_class = serializers.NodeGrantedSerializer
def list(self, request, *args, **kwargs):
nodes = self.get_nodes()
serializer = self.get_serializer(nodes, many=True)
return Response(serializer.data)
class BaseNodeChildrenApi(NodeChildrenMixin, BaseGrantedNodeApi, metaclass=abc.ABCMeta):
pass
class BaseGrantedNodeAsTreeApi(SerializeToTreeNodeMixin, _GrantedNodeStructApi, metaclass=abc.ABCMeta):
def list(self, request: Request, *args, **kwargs):
nodes = self.get_nodes()
nodes = self.serialize_nodes(nodes, with_asset_amount=True)
return Response(data=nodes)
class BaseNodeChildrenAsTreeApi(NodeChildrenMixin, BaseGrantedNodeAsTreeApi, metaclass=abc.ABCMeta):
pass
class UserGrantedNodeChildrenMixin:
user: User
request: Request
def get_children(self):
user = self.user
key = self.request.query_params.get('key')
nodes = UserGrantedNodesQueryUtils(user).get_node_children(key)
return nodes
class UserGrantedNodesMixin:
"""
查询用户授权的所有节点 直接授权节点 + 授权资产关联的节点
"""
user: User
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
return Node.objects.none()
return self.get_nodes()
@abc.abstractmethod
def get_nodes(self):
utils = UserGrantedNodesQueryUtils(self.user)
nodes = utils.get_whole_tree_nodes()
return nodes
return []
@lazyproperty
def query_node_util(self):
return UserGrantedNodesQueryUtils(self.user)
# API
class UserPermedNodeChildrenApi(
SelfOrPKUserMixin,
UserGrantedNodeChildrenMixin,
BaseNodeChildrenApi
):
""" 用户授权的节点下的子节点"""
pass
class UserPermedNodeChildrenAsTreeApi(
SelfOrPKUserMixin,
RebuildTreeMixin,
UserGrantedNodeChildrenMixin,
BaseNodeChildrenAsTreeApi
):
""" 用户授权的节点下的子节点树"""
pass
class UserPermedNodesApi(
SelfOrPKUserMixin,
UserGrantedNodesMixin,
BaseGrantedNodeApi
):
class UserAllPermedNodesApi(BaseUserPermedNodesApi):
""" 用户授权的节点 """
pass
def get_nodes(self):
return self.query_node_util.get_whole_tree_nodes()
class UserPermedNodesAsTreeApi(
SelfOrPKUserMixin,
RebuildTreeMixin,
UserGrantedNodesMixin,
BaseGrantedNodeAsTreeApi
):
""" 用户授权的节点树 """
pass
class UserPermedNodeChildrenApi(BaseUserPermedNodesApi):
""" 用户授权的节点下的子节点 """
def get_nodes(self):
key = self.request.query_params.get('key')
nodes = self.query_node_util.get_node_children(key)
return nodes

View File

@ -1,158 +0,0 @@
# -*- coding: utf-8 -*-
#
from django.conf import settings
from django.db.models import F, Value, CharField
from rest_framework.generics import ListAPIView
from rest_framework.request import Request
from rest_framework.response import Response
from common.utils import get_logger, get_object_or_none
from common.utils.common import timeit
from common.permissions import IsValidUser
from assets.models import Asset
from assets.api import SerializeToTreeNodeMixin
from perms.hands import Node
from perms.models import AssetPermission, PermNode
from perms.utils.user_permission import (
UserGrantedTreeBuildUtils, get_user_all_asset_perm_ids,
UserGrantedNodesQueryUtils, UserGrantedAssetsQueryUtils,
)
from .mixin import SelfOrPKUserMixin, RebuildTreeMixin
logger = get_logger(__name__)
class MyGrantedNodesWithAssetsAsTreeApi(SerializeToTreeNodeMixin, ListAPIView):
permission_classes = (IsValidUser,)
@timeit
def add_ungrouped_resource(self, data: list, nodes_query_utils, assets_query_utils):
if not settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
return
ungrouped_node = nodes_query_utils.get_ungrouped_node()
direct_granted_assets = assets_query_utils.get_direct_granted_assets().annotate(
parent_key=Value(ungrouped_node.key, output_field=CharField())
).prefetch_related('platform')
data.extend(self.serialize_nodes([ungrouped_node], with_asset_amount=True))
data.extend(self.serialize_assets(direct_granted_assets))
@timeit
def add_favorite_resource(self, data: list, nodes_query_utils, assets_query_utils):
favorite_node = nodes_query_utils.get_favorite_node()
favorite_assets = assets_query_utils.get_favorite_assets()
favorite_assets = favorite_assets.annotate(
parent_key=Value(favorite_node.key, output_field=CharField())
).prefetch_related('platform')
data.extend(self.serialize_nodes([favorite_node], with_asset_amount=True))
data.extend(self.serialize_assets(favorite_assets))
@timeit
def add_node_filtered_by_system_user(self, data: list, user, asset_perm_ids):
utils = UserGrantedTreeBuildUtils(user, asset_perm_ids)
nodes = utils.get_whole_tree_nodes()
data.extend(self.serialize_nodes(nodes, with_asset_amount=True))
def add_assets(self, data: list, assets_query_utils: UserGrantedAssetsQueryUtils):
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
all_assets = assets_query_utils.get_direct_granted_nodes_assets()
else:
all_assets = assets_query_utils.get_all_granted_assets()
all_assets = all_assets.annotate(parent_key=F('nodes__key')).prefetch_related('platform')
data.extend(self.serialize_assets(all_assets))
def list(self, request: Request, *args, **kwargs):
"""
此算法依赖 UserGrantedMappingNode
获取所有授权的节点和资产
Node = UserGrantedMappingNode + 授权节点的子节点
Asset = 授权节点的资产 + 直接授权的资产
"""
user = request.user
data = []
asset_perm_ids = get_user_all_asset_perm_ids(user)
system_user_id = request.query_params.get('system_user')
if system_user_id:
asset_perm_ids = list(AssetPermission.objects.valid().filter(
id__in=asset_perm_ids, system_users__id=system_user_id, actions__gt=0
).values_list('id', flat=True).distinct())
nodes_query_utils = UserGrantedNodesQueryUtils(user, asset_perm_ids)
assets_query_utils = UserGrantedAssetsQueryUtils(user, asset_perm_ids)
self.add_ungrouped_resource(data, nodes_query_utils, assets_query_utils)
self.add_favorite_resource(data, nodes_query_utils, assets_query_utils)
if system_user_id:
# 有系统用户筛选的需要重新计算树结构
self.add_node_filtered_by_system_user(data, user, asset_perm_ids)
else:
all_nodes = nodes_query_utils.get_whole_tree_nodes(with_special=False)
data.extend(self.serialize_nodes(all_nodes, with_asset_amount=True))
self.add_assets(data, assets_query_utils)
return Response(data=data)
class GrantedNodeChildrenWithAssetsAsTreeApiMixin(SerializeToTreeNodeMixin,
ListAPIView):
"""
带资产的授权树
"""
user: None
def ensure_key(self):
key = self.request.query_params.get('key', None)
id = self.request.query_params.get('id', None)
if key is not None:
return key
node = get_object_or_none(Node, id=id)
if node:
return node.key
def list(self, request: Request, *args, **kwargs):
user = self.user
key = self.ensure_key()
nodes_query_utils = UserGrantedNodesQueryUtils(user)
assets_query_utils = UserGrantedAssetsQueryUtils(user)
nodes = PermNode.objects.none()
assets = Asset.objects.none()
all_tree_nodes = []
if not key:
nodes = nodes_query_utils.get_top_level_nodes()
elif key == PermNode.UNGROUPED_NODE_KEY:
assets = assets_query_utils.get_ungroup_assets()
elif key == PermNode.FAVORITE_NODE_KEY:
assets = assets_query_utils.get_favorite_assets()
else:
nodes = nodes_query_utils.get_node_children(key)
assets = assets_query_utils.get_node_assets(key)
assets = assets.prefetch_related('platform')
tree_nodes = self.serialize_nodes(nodes, with_asset_amount=True)
tree_assets = self.serialize_assets(assets, key)
all_tree_nodes.extend(tree_nodes)
all_tree_nodes.extend(tree_assets)
return Response(data=all_tree_nodes)
class UserGrantedNodeChildrenWithAssetsAsTreeApi(
SelfOrPKUserMixin,
RebuildTreeMixin,
GrantedNodeChildrenWithAssetsAsTreeApiMixin
):
""" 用户授权的节点的子节点与资产树 """
pass

View File

@ -0,0 +1,3 @@
from .asset import *
from .node import *
from .node_with_asset import *

View File

@ -0,0 +1,48 @@
from django.conf import settings
from rest_framework.response import Response
from assets.models import Asset
from assets.api import SerializeToTreeNodeMixin
from common.utils import get_logger
from ..assets import UserDirectPermedAssetsApi
from .mixin import RebuildTreeMixin
logger = get_logger(__name__)
__all__ = [
'UserDirectPermedAssetsAsTreeApi',
'UserUngroupAssetsAsTreeApi',
]
class AssetTreeMixin(RebuildTreeMixin, SerializeToTreeNodeMixin):
""" 将资产序列化成树节点的结构返回 """
filter_queryset: callable
get_queryset: callable
ordering = ('name',)
filterset_fields = ('id', 'name', 'address', 'comment')
search_fields = ('name', 'address', 'comment')
def list(self, request, *args, **kwargs):
assets = self.filter_queryset(self.get_queryset())
if request.query_params.get('search'):
""" 限制返回数量, 搜索的条件不精准时,会返回大量的无意义数据 """
assets = assets[:999]
data = self.serialize_assets(assets, None)
return Response(data=data)
class UserDirectPermedAssetsAsTreeApi(AssetTreeMixin, UserDirectPermedAssetsApi):
""" 用户 '直接授权的资产' 作为树 """
pass
class UserUngroupAssetsAsTreeApi(UserDirectPermedAssetsAsTreeApi):
""" 用户 '未分组节点的资产(直接授权的资产)' 作为树 """
def get_assets(self):
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
return super().get_assets()
return Asset.objects.none()

View File

@ -0,0 +1,17 @@
from rest_framework.request import Request
from users.models import User
from perms.utils.user_permission import UserGrantedTreeRefreshController
from common.http import is_true
__all__ = ['RebuildTreeMixin']
class RebuildTreeMixin:
user: User
def get(self, request: Request, *args, **kwargs):
force = is_true(request.query_params.get('rebuild_tree'))
UserGrantedTreeRefreshController(self.user).refresh_if_need(force)
return super().get(request, *args, **kwargs)

View File

@ -0,0 +1,39 @@
from rest_framework.response import Response
from assets.api import SerializeToTreeNodeMixin
from common.utils import get_logger
from .mixin import RebuildTreeMixin
from ..nodes import (
UserAllPermedNodesApi,
UserPermedNodeChildrenApi,
)
logger = get_logger(__name__)
__all__ = [
'UserAllPermedNodesAsTreeApi',
'UserPermedNodeChildrenAsTreeApi',
]
class NodeTreeMixin(RebuildTreeMixin, SerializeToTreeNodeMixin):
filter_queryset: callable
get_queryset: callable
def list(self, request, *args, **kwargs):
nodes = self.filter_queryset(self.get_queryset())
data = self.serialize_nodes(nodes, with_asset_amount=True)
return Response(data)
class UserAllPermedNodesAsTreeApi(NodeTreeMixin, UserAllPermedNodesApi):
""" 用户 '授权的节点' 作为树 """
pass
class UserPermedNodeChildrenAsTreeApi(NodeTreeMixin, UserPermedNodeChildrenApi):
""" 用户授权的节点下的子节点树 """
pass

View File

@ -0,0 +1,125 @@
import abc
from django.conf import settings
from django.db.models import F, Value, CharField
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from assets.models import Asset
from assets.api import SerializeToTreeNodeMixin
from perms.hands import Node
from perms.models import PermNode
from perms.utils.user_permission import (
UserGrantedNodesQueryUtils, UserGrantedAssetsQueryUtils,
)
from perms.utils.permission import AssetPermissionUtil
from common.utils import get_object_or_none, lazyproperty
from common.utils.common import timeit
from ..mixin import SelfOrPKUserMixin
from .mixin import RebuildTreeMixin
__all__ = [
'UserPermedNodesWithAssetsAsTreeApi',
'UserPermedNodeChildrenWithAssetsAsTreeApi'
]
class BaseUserNodeWithAssetAsTreeApi(SelfOrPKUserMixin, RebuildTreeMixin, SerializeToTreeNodeMixin,
ListAPIView):
def list(self, request, *args, **kwargs):
nodes, assets = self.get_nodes_assets()
tree_nodes = self.serialize_nodes(nodes, with_asset_amount=True)
tree_assets = self.serialize_assets(assets, node_key=self.node_key_for_serializer_assets)
data = list(tree_nodes) + list(tree_assets)
return Response(data=data)
@abc.abstractmethod
def get_nodes_assets(self):
return [], []
@lazyproperty
def node_key_for_serializer_assets(self):
return None
class UserPermedNodesWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
query_node_util: UserGrantedNodesQueryUtils
query_asset_util: UserGrantedAssetsQueryUtils
def get_nodes_assets(self):
perm_ids = AssetPermissionUtil().get_permissions_for_user(self.request.user, flat=True)
self.query_node_util = UserGrantedNodesQueryUtils(self.request.user, perm_ids)
self.query_asset_util = UserGrantedAssetsQueryUtils(self.request.user, perm_ids)
ung_nodes, ung_assets = self._get_nodes_assets_for_ungrouped()
fav_nodes, fav_assets = self._get_nodes_assets_for_favorite()
all_nodes, all_assets = self._get_nodes_assets_for_all()
nodes = list(ung_nodes) + list(fav_nodes) + list(all_nodes)
assets = list(ung_assets) + list(fav_assets) + list(all_assets)
return nodes, assets
@timeit
def _get_nodes_assets_for_ungrouped(self):
if not settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
return [], []
node = self.query_node_util.get_ungrouped_node()
assets = self.query_asset_util.get_ungroup_assets()
assets = assets.annotate(parent_key=Value(node.key, output_field=CharField())) \
.prefetch_related('platform')
return [node], assets
@timeit
def _get_nodes_assets_for_favorite(self):
node = self.query_node_util.get_favorite_node()
assets = self.query_asset_util.get_favorite_assets()
assets = assets.annotate(parent_key=Value(node.key, output_field=CharField())) \
.prefetch_related('platform')
return [node], assets
def _get_nodes_assets_for_all(self):
nodes = self.query_node_util.get_whole_tree_nodes(with_special=False)
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
assets = self.query_asset_util.get_direct_granted_nodes_assets()
else:
assets = self.query_asset_util.get_all_granted_assets()
assets = assets.annotate(parent_key=F('nodes__key')).prefetch_related('platform')
return nodes, assets
class UserPermedNodeChildrenWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi):
""" 用户授权的节点的子节点与资产树 """
def get_nodes_assets(self):
nodes = PermNode.objects.none()
assets = Asset.objects.none()
query_node_util = UserGrantedNodesQueryUtils(self.user)
query_asset_util = UserGrantedAssetsQueryUtils(self.user)
node_key = self.query_node_key
if not node_key:
nodes = query_node_util.get_top_level_nodes()
elif node_key == PermNode.UNGROUPED_NODE_KEY:
assets = query_asset_util.get_ungroup_assets()
elif node_key == PermNode.FAVORITE_NODE_KEY:
assets = query_asset_util.get_favorite_assets()
else:
nodes = query_node_util.get_node_children(node_key)
assets = query_asset_util.get_node_assets(node_key)
assets = assets.prefetch_related('platform')
return nodes, assets
@lazyproperty
def query_node_key(self):
node_key = self.request.query_params.get('key', None)
if node_key is not None:
return node_key
node_id = self.request.query_params.get('id', None)
node = get_object_or_none(Node, id=node_id)
node_key = getattr(node, 'key', None)
return node_key
@lazyproperty
def node_key_for_serializer_assets(self):
return self.query_node_key

View File

@ -16,7 +16,7 @@ class GrantedAssetPaginationBase(AssetPaginationBase):
self._user = view.user
class NodeGrantedAssetPagination(GrantedAssetPaginationBase):
class NodePermedAssetPagination(GrantedAssetPaginationBase):
def get_count_from_nodes(self, queryset):
node = getattr(self._view, 'pagination_node', None)
if node:
@ -29,7 +29,7 @@ class NodeGrantedAssetPagination(GrantedAssetPaginationBase):
return None
class AllGrantedAssetPagination(GrantedAssetPaginationBase):
class AllPermedAssetPagination(GrantedAssetPaginationBase):
def get_count_from_nodes(self, queryset):
if settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
return None

View File

@ -11,12 +11,12 @@ from common.drf.fields import ObjectRelatedField, LabeledChoiceField
from perms.serializers.permission import ActionChoicesField
__all__ = [
'NodeGrantedSerializer', 'AssetGrantedSerializer',
'NodeGrantedSerializer', 'AssetPermedSerializer',
'AccountsPermedSerializer'
]
class AssetGrantedSerializer(serializers.ModelSerializer):
class AssetPermedSerializer(serializers.ModelSerializer):
""" 被授权资产的数据结构 """
platform = ObjectRelatedField(required=False, queryset=Platform.objects, label=_('Platform'))
protocols = AssetProtocolsSerializer(many=True, required=False, label=_('Protocols'))

View File

@ -4,39 +4,38 @@ from .. import api
user_permission_urlpatterns = [
# <str:user> such as: my | self | user.id
# assets
path('<str:user>/assets/', api.UserAllPermedAssetsApi.as_view(),
name='user-assets'),
path('<str:user>/assets/tree/', api.UserDirectPermedAssetsAsTreeApi.as_view(),
name='user-assets-as-tree'),
path('<str:user>/ungroup/assets/tree/', api.UserUngroupAssetsAsTreeApi.as_view(),
name='user-ungroup-assets-as-tree'),
# nodes
path('<str:user>/nodes/', api.UserPermedNodesApi.as_view(),
name='user-nodes'),
path('<str:user>/nodes/tree/', api.UserPermedNodesAsTreeApi.as_view(),
name='user-nodes-as-tree'),
path('<str:user>/nodes/children/', api.UserPermedNodeChildrenApi.as_view(),
name='user-nodes-children'),
path('<str:user>/nodes/children/tree/', api.UserPermedNodeChildrenAsTreeApi.as_view(),
name='user-nodes-children-as-tree'),
# node-assets
name='user-all-assets'),
path('<str:user>/nodes/ungrouped/assets/', api.UserDirectPermedAssetsApi.as_view(),
name='user-direct-assets'),
path('<str:user>/nodes/favorite/assets/', api.UserFavoriteAssetsApi.as_view(),
name='user-favorite-assets'),
path('<str:user>/nodes/<uuid:node_id>/assets/', api.UserPermedNodeAssetsApi.as_view(),
name='user-node-assets'),
path('<str:user>/nodes/ungrouped/assets/', api.UserDirectPermedAssetsApi.as_view(),
name='user-ungrouped-assets'),
path('<str:user>/nodes/favorite/assets/', api.UserFavoriteAssetsApi.as_view(),
name='user-ungrouped-assets'),
# nodes
path('<str:user>/nodes/', api.UserAllPermedNodesApi.as_view(),
name='user-all-nodes'),
path('<str:user>/nodes/children/', api.UserPermedNodeChildrenApi.as_view(),
name='user-node-children'),
# tree-asset
path('<str:user>/assets/tree/', api.UserDirectPermedAssetsAsTreeApi.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'),
# tree-node-with-asset
path('<str:user>/nodes/children-with-assets/tree/',
api.UserGrantedNodeChildrenWithAssetsAsTreeApi.as_view(),
name='user-nodes-children-with-assets-as-tree'),
path('nodes-with-assets/tree/', api.MyGrantedNodesWithAssetsAsTreeApi.as_view(),
name='my-nodes-with-assets-as-tree'),
api.UserPermedNodeChildrenWithAssetsAsTreeApi.as_view(),
name='user-node-children-with-assets-as-tree'),
path('<str:user>/nodes-with-assets/tree/', api.UserPermedNodesWithAssetsAsTreeApi.as_view(),
name='user-nodes-with-assets-as-tree'),
# accounts
path('<str:user>/assets/<uuid:asset_id>/accounts/', api.UserPermedAssetAccountsApi.as_view(),

View File

@ -4,6 +4,8 @@ from perms.models import AssetPermission
logger = get_logger(__file__)
__all__ = ['AssetPermissionUtil']
class AssetPermissionUtil(object):
""" 资产授权相关的方法工具 """