perf: 优化用户授权 api

pull/9151/head
ibuler 2022-12-02 13:15:03 +08:00
parent 61e6ab20a2
commit 2d771eedc1
6 changed files with 109 additions and 154 deletions

View File

@ -37,7 +37,10 @@ class AssetFilterSet(BaseFilterSet):
class Meta:
model = Asset
fields = ["name", "address", "is_active", "type", "category", "hostname"]
fields = [
"id", "name", "address", "is_active",
"type", "category", "hostname"
]
class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet):

View File

@ -1,25 +1,37 @@
from rest_framework.request import Request
from rest_framework.response import Response
from django.conf import settings
from rest_framework.generics import ListAPIView
from common.utils import get_logger
from users.models import User
from assets.api.asset.asset import AssetFilterSet
from assets.api.mixin import SerializeToTreeNodeMixin
from assets.models import Asset, Node
from common.utils import get_logger
from perms import serializers
from perms.pagination import NodeGrantedAssetPagination, AllGrantedAssetPagination
from perms.pagination import AllGrantedAssetPagination
from perms.pagination import NodeGrantedAssetPagination
from perms.utils.user_permission import UserGrantedAssetsQueryUtils
from .mixin import (
SelfOrPKUserMixin, RebuildTreeMixin,
PermedAssetSerializerMixin, AssetsTreeFormatMixin
)
__all__ = [
'UserDirectPermedAssetsApi',
'UserFavoriteAssetsApi',
'UserDirectPermedAssetsAsTreeApi',
'UserUngroupAssetsAsTreeApi',
'UserAllPermedAssetsApi',
'UserPermedNodeAssetsApi',
]
logger = get_logger(__name__)
class UserDirectGrantedAssetsQuerysetMixin:
class UserDirectPermedAssetsApi(SelfOrPKUserMixin, PermedAssetSerializerMixin, ListAPIView):
""" 直接授权给用户的资产 """
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
user: User
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') \
@ -27,14 +39,49 @@ class UserDirectGrantedAssetsQuerysetMixin:
return assets
class UserAllGrantedAssetsQuerysetMixin:
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 = assets.prefetch_related('platform').only(*self.only_fields)
return assets
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
class UserUngroupAssetsAsTreeApi(UserDirectPermedAssetsAsTreeApi):
""" 用户未分组节点下的资产作为树 """
def get_queryset(self):
queryset = super().get_queryset()
if not settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
queryset = queryset.none()
return queryset
class UserAllPermedAssetsApi(SelfOrPKUserMixin, PermedAssetSerializerMixin, ListAPIView):
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
pagination_class = AllGrantedAssetPagination
ordering_fields = ("name", "address")
filterset_class = AssetFilterSet
ordering = ('name',)
user: User
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
@ -45,26 +92,11 @@ class UserAllGrantedAssetsQuerysetMixin:
return queryset
class UserFavoriteGrantedAssetsMixin:
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
user: User
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 = assets.prefetch_related('platform').only(*self.only_fields)
return assets
class UserGrantedNodeAssetsMixin:
class UserPermedNodeAssetsApi(SelfOrPKUserMixin, PermedAssetSerializerMixin, ListAPIView):
only_fields = serializers.AssetGrantedSerializer.Meta.only_fields
pagination_class = NodeGrantedAssetPagination
pagination_node: Node
user: User
kwargs: dict
pagination_node: Node
def get_queryset(self):
if getattr(self, 'swagger_fake_view', False):
@ -75,34 +107,3 @@ class UserGrantedNodeAssetsMixin:
assets = assets.prefetch_related('platform').only(*self.only_fields)
self.pagination_node = node
return assets
class AssetSerializerFormatMixin:
serializer_class = serializers.AssetGrantedSerializer
filterset_fields = ['name', 'address', 'id', 'comment']
search_fields = ['name', 'address', 'comment']
filterset_class = AssetFilterSet
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 +0,0 @@
from .api import *

View File

@ -1,82 +0,0 @@
from django.conf import settings
from rest_framework.generics import ListAPIView
from common.utils import get_logger
from .mixin import (
AssetsTreeFormatMixin,
UserGrantedNodeAssetsMixin,
AssetSerializerFormatMixin,
UserFavoriteGrantedAssetsMixin,
UserAllGrantedAssetsQuerysetMixin,
UserDirectGrantedAssetsQuerysetMixin,
)
from ..mixin import SelfOrPKUserMixin, RebuildTreeMixin
__all__ = [
'UserDirectGrantedAssetsApi',
'UserFavoriteGrantedAssetsApi',
'UserDirectGrantedAssetsAsTreeApi',
'UserUngroupAssetsAsTreeApi',
'UserAllGrantedAssetsApi',
'UserGrantedNodeAssetsApi',
]
logger = get_logger(__name__)
class UserDirectGrantedAssetsApi(
SelfOrPKUserMixin,
UserDirectGrantedAssetsQuerysetMixin,
AssetSerializerFormatMixin,
ListAPIView
):
""" 直接授权给用户的资产 """
pass
class UserFavoriteGrantedAssetsApi(
SelfOrPKUserMixin,
UserFavoriteGrantedAssetsMixin,
AssetSerializerFormatMixin,
ListAPIView
):
""" 用户收藏的授权资产 """
pass
class UserDirectGrantedAssetsAsTreeApi(
RebuildTreeMixin,
AssetsTreeFormatMixin,
UserDirectGrantedAssetsApi
):
""" 用户直接授权的资产作为树 """
pass
class UserUngroupAssetsAsTreeApi(UserDirectGrantedAssetsAsTreeApi):
""" 用户未分组节点下的资产作为树 """
def get_queryset(self):
queryset = super().get_queryset()
if not settings.PERM_SINGLE_ASSET_TO_UNGROUP_NODE:
queryset = queryset.none()
return queryset
class UserAllGrantedAssetsApi(
SelfOrPKUserMixin,
UserAllGrantedAssetsQuerysetMixin,
AssetSerializerFormatMixin,
ListAPIView
):
""" 授权给用户的所有资产 """
pass
class UserGrantedNodeAssetsApi(
SelfOrPKUserMixin,
UserGrantedNodeAssetsMixin,
AssetSerializerFormatMixin,
ListAPIView
):
""" 授权给用户的节点资产 """
pass

View File

@ -1,12 +1,16 @@
# -*- coding: utf-8 -*-
#
from django.shortcuts import get_object_or_404
from rest_framework.request import Request
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 common.exceptions import JMSObjectDoesNotExist
from perms import serializers
from perms.utils.user_permission import UserGrantedTreeRefreshController
from rbac.permissions import RBACPermission
from users.models import User
@ -67,3 +71,33 @@ 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

@ -6,9 +6,9 @@ user_permission_urlpatterns = [
# <str:user> such as: my | self | user.id
# assets
path('<str:user>/assets/', api.UserAllGrantedAssetsApi.as_view(),
path('<str:user>/assets/', api.UserAllPermedAssetsApi.as_view(),
name='user-assets'),
path('<str:user>/assets/tree/', api.UserDirectGrantedAssetsAsTreeApi.as_view(),
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'),
@ -24,11 +24,11 @@ user_permission_urlpatterns = [
name='user-nodes-children-as-tree'),
# node-assets
path('<str:user>/nodes/<uuid:node_id>/assets/', api.UserGrantedNodeAssetsApi.as_view(),
path('<str:user>/nodes/<uuid:node_id>/assets/', api.UserPermedNodeAssetsApi.as_view(),
name='user-node-assets'),
path('<str:user>/nodes/ungrouped/assets/', api.UserDirectGrantedAssetsApi.as_view(),
path('<str:user>/nodes/ungrouped/assets/', api.UserDirectPermedAssetsApi.as_view(),
name='user-ungrouped-assets'),
path('<str:user>/nodes/favorite/assets/', api.UserFavoriteGrantedAssetsApi.as_view(),
path('<str:user>/nodes/favorite/assets/', api.UserFavoriteAssetsApi.as_view(),
name='user-ungrouped-assets'),
path('<str:user>/nodes/children-with-assets/tree/',