diff --git a/apps/perms/api/user_permission/tree/mixin.py b/apps/perms/api/user_permission/tree/mixin.py index 6c5eaac47..c0cafe37c 100644 --- a/apps/perms/api/user_permission/tree/mixin.py +++ b/apps/perms/api/user_permission/tree/mixin.py @@ -1,6 +1,9 @@ +from django.core.cache import cache + from rest_framework.request import Request from common.http import is_true +from common.utils import lazyproperty from perms.utils import UserPermTreeRefreshUtil from users.models import User @@ -9,8 +12,29 @@ __all__ = ['RebuildTreeMixin'] class RebuildTreeMixin: user: User + request: Request - def get(self, request: Request, *args, **kwargs): - force = is_true(request.query_params.get('rebuild_tree')) - UserPermTreeRefreshUtil(self.user).refresh_if_need(force) + def get(self, request, *args, **kwargs): + UserPermTreeRefreshUtil(self.user).refresh_if_need(force=self.is_force_refresh_tree) return super().get(request, *args, **kwargs) + + @lazyproperty + def is_force_refresh_tree(self): + force = is_true(self.request.query_params.get('rebuild_tree')) + if not force: + force = self.compute_is_force_refresh() + return force + + def compute_is_force_refresh(self): + """ 5s 内连续刷新三次转为强制刷新 """ + force_timeout = 5 + force_max_count = 3 + force_cache_key = '{user_id}:{path}'.format(user_id=self.user.id, path=self.request.path) + count = cache.get(force_cache_key, 1) + if count >= force_max_count: + force = True + cache.delete(force_cache_key) + else: + force = False + cache.set(force_cache_key, count+1, force_timeout) + return force diff --git a/apps/perms/api/user_permission/tree/node_with_asset.py b/apps/perms/api/user_permission/tree/node_with_asset.py index bb36b77ef..1dcdcc43d 100644 --- a/apps/perms/api/user_permission/tree/node_with_asset.py +++ b/apps/perms/api/user_permission/tree/node_with_asset.py @@ -37,7 +37,7 @@ class BaseUserNodeWithAssetAsTreeApi( 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) + tree_assets = self.serialize_assets(assets, node_key=self.node_key_for_serialize_assets) data = list(tree_nodes) + list(tree_assets) return Response(data=data) @@ -46,7 +46,7 @@ class BaseUserNodeWithAssetAsTreeApi( return [], [] @lazyproperty - def node_key_for_serializer_assets(self): + def node_key_for_serialize_assets(self): return None @@ -95,19 +95,21 @@ class UserPermedNodesWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi): class UserPermedNodeChildrenWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi): """ 用户授权的节点的子节点与资产树 """ + # 默认展开的节点key + default_unfolded_node_key = None + def get_nodes_assets(self): query_node_util = UserPermNodeUtil(self.user) query_asset_util = UserPermAssetUtil(self.user) node_key = self.query_node_key if not node_key: - nodes = query_node_util.get_top_level_nodes() - assets = Asset.objects.none() - # 获取根节点下的资产 - for node in nodes: - if not node.key.isdigit(): - continue - assets = query_asset_util.get_node_assets(key=node.key) - break + nodes, unfolded_node = query_node_util.get_top_level_nodes(with_unfolded_node=True) + if unfolded_node: + """ 默认展开的节点, 获取根节点下的资产 """ + assets = query_asset_util.get_node_assets(key=unfolded_node.key) + self.default_unfolded_node_key = unfolded_node.key + else: + assets = Asset.objects.none() elif node_key == PermNode.UNGROUPED_NODE_KEY: nodes = PermNode.objects.none() assets = query_asset_util.get_ungroup_assets() @@ -123,16 +125,15 @@ class UserPermedNodeChildrenWithAssetsAsTreeApi(BaseUserNodeWithAssetAsTreeApi): @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) + if node_key is None: + 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 + def node_key_for_serialize_assets(self): + return self.query_node_key or self.default_unfolded_node_key class UserGrantedK8sAsTreeApi(SelfOrPKUserMixin, ListAPIView): diff --git a/apps/perms/utils/user_perm.py b/apps/perms/utils/user_perm.py index 96644c03e..ceea59b22 100644 --- a/apps/perms/utils/user_perm.py +++ b/apps/perms/utils/user_perm.py @@ -148,15 +148,20 @@ class UserPermNodeUtil: assets_amount = UserPermAssetUtil(self.user).get_direct_assets().count() return PermNode.get_favorite_node(assets_amount) - def get_top_level_nodes(self): + def get_top_level_nodes(self, with_unfolded_node=False): + # 是否有节点展开, 展开的节点 + unfolded_node = None nodes = self.get_special_nodes() - # 获取组织下的根节点 - real_nodes = self._get_indirect_perm_node_children(key='') + real_nodes = self._get_perm_node_children_from_relation(key='') nodes.extend(real_nodes) if len(real_nodes) == 1: - children = self.get_node_children(real_nodes[0].key) + unfolded_node = real_nodes[0] + children = self.get_node_children(unfolded_node.key) nodes.extend(children) - return nodes + if with_unfolded_node: + return nodes, unfolded_node + else: + return nodes def get_special_nodes(self): nodes = [] @@ -177,16 +182,18 @@ class UserPermNodeUtil: node = PermNode.objects.get(key=key) node.compute_node_from_and_assets_amount(self.user) if node.node_from == node.NodeFrom.granted: + """ 直接授权的节点, 直接从完整资产树获取子节点 """ children = PermNode.objects.filter(parent_key=key) elif node.node_from in (node.NodeFrom.asset, node.NodeFrom.child): - children = self._get_indirect_perm_node_children(key) + """ 间接授权的节点, 从 Relation 表中获取子节点 """ + children = self._get_perm_node_children_from_relation(key) else: children = PermNode.objects.none() children = sorted(children, key=lambda x: x.value) return children - def _get_indirect_perm_node_children(self, key): - """ 获取未直接授权节点的子节点 """ + def _get_perm_node_children_from_relation(self, key): + """ 获取授权节点的子节点, 从用户授权节点关系表中获取 """ children = PermNode.objects.filter(granted_node_rels__user=self.user, parent_key=key) children = children.annotate(**PermNode.annotate_granted_node_rel_fields).distinct() for node in children: