Unverified Commit de43980e authored by 老广's avatar 老广 Committed by GitHub

Dev beta2 (#3177)

* [Update] 添加loading

* [Update] stash

* [Update] 修改permission
parent d5dcab15
...@@ -34,7 +34,6 @@ var actions = { ...@@ -34,7 +34,6 @@ var actions = {
}}; }};
$(document).ready(function () { $(document).ready(function () {
initTree(); initTree();
initTable();
}).on('click', '.labels li', function () { }).on('click', '.labels li', function () {
var val = $(this).text(); var val = $(this).text();
$("#user_assets_table_filter input").val(val); $("#user_assets_table_filter input").val(val);
......
...@@ -51,15 +51,15 @@ urlpatterns = [ ...@@ -51,15 +51,15 @@ urlpatterns = [
path('system-users/<uuid:pk>/auth-info/', path('system-users/<uuid:pk>/auth-info/',
api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'), api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'),
path('system-users/<uuid:pk>/asset/<uuid:aid>/auth-info/', path('system-users/<uuid:pk>/assets/<uuid:aid>/auth-info/',
api.SystemUserAssetAuthInfoApi.as_view(), name='system-user-asset-auth-info'), api.SystemUserAssetAuthInfoApi.as_view(), name='system-user-asset-auth-info'),
path('system-users/<uuid:pk>/assets/', path('system-users/<uuid:pk>/assets/',
api.SystemUserAssetsListView.as_view(), name='system-user-assets'), api.SystemUserAssetsListView.as_view(), name='system-user-assets'),
path('system-users/<uuid:pk>/push/', path('system-users/<uuid:pk>/push/',
api.SystemUserPushApi.as_view(), name='system-user-push'), api.SystemUserPushApi.as_view(), name='system-user-push'),
path('system-users/<uuid:pk>/asset/<uuid:aid>/push/', path('system-users/<uuid:pk>/assets/<uuid:aid>/push/',
api.SystemUserPushToAssetApi.as_view(), name='system-user-push-to-asset'), api.SystemUserPushToAssetApi.as_view(), name='system-user-push-to-asset'),
path('system-users/<uuid:pk>/asset/<uuid:aid>/test/', path('system-users/<uuid:pk>/assets/<uuid:aid>/test/',
api.SystemUserTestAssetConnectivityApi.as_view(), name='system-user-test-to-asset'), api.SystemUserTestAssetConnectivityApi.as_view(), name='system-user-test-to-asset'),
path('system-users/<uuid:pk>/connective/', path('system-users/<uuid:pk>/connective/',
api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'), api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'),
......
...@@ -66,27 +66,23 @@ class TreeService(Tree): ...@@ -66,27 +66,23 @@ class TreeService(Tree):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.nodes_assets_map = defaultdict(set) self.nodes_assets_map = defaultdict(set)
self.all_nodes_assets_map = {} self.all_nodes_assets_map = {}
self.mutex = threading.Lock()
@classmethod @classmethod
@timeit @timeit
def new(cls): def new(cls):
from .models import Node from .models import Node
from orgs.utils import get_current_org, set_to_root_org from orgs.utils import tmp_to_root_org
origin_org = get_current_org() with tmp_to_root_org():
set_to_root_org() all_nodes = Node.objects.all()
all_nodes = Node.objects.all() tree = cls()
origin_org.change_to() tree.create_node(tag='', identifier='')
for node in all_nodes:
tree = cls() tree.create_node(
tree.create_node(tag='', identifier='') tag=node.value, identifier=node.key,
for node in all_nodes: parent=node.parent_key,
tree.create_node( )
tag=node.value, identifier=node.key, tree.init_assets()
parent=node.parent_key,
)
tree.init_assets_async()
return tree return tree
def init_assets_async(self): def init_assets_async(self):
...@@ -95,17 +91,16 @@ class TreeService(Tree): ...@@ -95,17 +91,16 @@ class TreeService(Tree):
def init_assets(self): def init_assets(self):
from orgs.utils import get_current_org, set_to_root_org from orgs.utils import get_current_org, set_to_root_org
with self.mutex: origin_org = get_current_org()
origin_org = get_current_org() set_to_root_org()
set_to_root_org() queryset = Asset.objects.all().valid().values_list('id', 'nodes__key')
queryset = Asset.objects.all().valid().values_list('id', 'nodes__key')
if origin_org:
if origin_org: origin_org.change_to()
origin_org.change_to() for asset_id, key in queryset:
for asset_id, key in queryset: if not key:
if not key: continue
continue self.nodes_assets_map[key].add(asset_id)
self.nodes_assets_map[key].add(asset_id)
def all_children(self, nid, with_self=True, deep=False): def all_children(self, nid, with_self=True, deep=False):
children_ids = self.expand_tree(nid) children_ids = self.expand_tree(nid)
...@@ -146,13 +141,11 @@ class TreeService(Tree): ...@@ -146,13 +141,11 @@ class TreeService(Tree):
return parent return parent
def assets(self, nid): def assets(self, nid):
with self.mutex: assets = self.nodes_assets_map[nid]
assets = self.nodes_assets_map[nid] return assets
return assets
def set_assets(self, nid, assets): def set_assets(self, nid, assets):
with self.mutex: self.nodes_assets_map[nid] = assets
self.nodes_assets_map[nid] = assets
def all_assets(self, nid): def all_assets(self, nid):
assets = self.all_nodes_assets_map.get(nid) assets = self.all_nodes_assets_map.get(nid)
...@@ -186,12 +179,17 @@ class TreeService(Tree): ...@@ -186,12 +179,17 @@ class TreeService(Tree):
self.safe_add_ancestors(ancestors) self.safe_add_ancestors(ancestors)
parent = self.get_node(parent_id) parent = self.get_node(parent_id)
print("Add node: {} {}".format(node.identifier, parent.identifier))
# 如果当前节点已再树中,则移动当前节点到父节点中 # 如果当前节点已再树中,则移动当前节点到父节点中
# 这个是由于 当前节点放到了二级节点中 # 这个是由于 当前节点放到了二级节点中
if self.contains(node.identifier): if self.contains(node.identifier):
self.move_node(node.identifier, parent.identifier) self.move_node(node.identifier, parent.identifier)
else: else:
self.add_node(node, parent) self.add_node(node, parent)
#
# def __getstate__(self):
# self.mutex = None
# return self.__dict__
#
# def __setstate__(self, state):
# self.__dict__ = state
# self.mutex = threading.Lock()
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf.urls import url from django.urls.conf import re_path
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from common import api as capi
from .. import api from .. import api
app_name = "audits" app_name = "audits"
router = DefaultRouter() router = DefaultRouter()
router.register(r'ftp-log', api.FTPLogViewSet, 'ftp-log') router.register(r'ftp-logs', api.FTPLogViewSet, 'ftp-log')
urlpatterns = [ urlpatterns = [
] ]
old_version_urlpatterns = [
re_path('(?P<resource>ftp-log)/.*', capi.redirect_plural_name_api)
]
urlpatterns += router.urls urlpatterns += router.urls
...@@ -12,11 +12,14 @@ from rest_framework import generics, serializers ...@@ -12,11 +12,14 @@ from rest_framework import generics, serializers
from .http import HttpResponseTemporaryRedirect from .http import HttpResponseTemporaryRedirect
from .const import KEY_CACHE_RESOURCES_ID from .const import KEY_CACHE_RESOURCES_ID
from .utils import get_logger
__all__ = [ __all__ = [
'LogTailApi', 'ResourcesIDCacheApi', 'LogTailApi', 'ResourcesIDCacheApi',
] ]
logger = get_logger(__file__)
class OutputSerializer(serializers.Serializer): class OutputSerializer(serializers.Serializer):
output = serializers.CharField() output = serializers.CharField()
...@@ -93,6 +96,7 @@ class ResourcesIDCacheApi(APIView): ...@@ -93,6 +96,7 @@ class ResourcesIDCacheApi(APIView):
@csrf_exempt @csrf_exempt
def redirect_plural_name_api(request, *args, **kwargs): def redirect_plural_name_api(request, *args, **kwargs):
resource = kwargs.get("resource", "") resource = kwargs.get("resource", "")
full_path = request.get_full_path() org_full_path = request.get_full_path()
full_path = full_path.replace(resource, resource+"s", 1) full_path = org_full_path.replace(resource, resource+"s", 1)
logger.debug("Redirect {} => {}".format(org_full_path, full_path))
return HttpResponseTemporaryRedirect(full_path) return HttpResponseTemporaryRedirect(full_path)
...@@ -10,9 +10,10 @@ from . import user_permission as uapi ...@@ -10,9 +10,10 @@ from . import user_permission as uapi
__all__ = [ __all__ = [
'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi', 'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi',
'UserGroupGrantedNodeAssetsApi', 'UserGroupGrantedNodeChildrenApi', 'UserGroupGrantedNodeAssetsApi', 'UserGroupGrantedNodeChildrenApi',
'UserGroupGrantedNodeChildrenAsTreeApi', 'UserGroupGrantedNodesWithAssetsAsTreeApi', 'UserGroupGrantedNodeChildrenAsTreeApi',
'UserGroupGrantedNodeChildrenWithAssetsAsTreeApi',
'UserGroupGrantedAssetSystemUsersApi', 'UserGroupGrantedAssetSystemUsersApi',
# 'UserGroupGrantedNodesWithAssetsAsTreeApi', # 'UserGroupGrantedNodeChildrenWithAssetsAsTreeApi',
] ]
...@@ -45,7 +46,7 @@ class UserGroupGrantedNodeChildrenAsTreeApi(UserGroupPermissionMixin, uapi.UserG ...@@ -45,7 +46,7 @@ class UserGroupGrantedNodeChildrenAsTreeApi(UserGroupPermissionMixin, uapi.UserG
pass pass
class UserGroupGrantedNodesWithAssetsAsTreeApi(UserGroupPermissionMixin, uapi.UserGrantedNodesWithAssetsAsTreeApi): class UserGroupGrantedNodeChildrenWithAssetsAsTreeApi(UserGroupPermissionMixin, uapi.UserGrantedNodeChildrenWithAssetsAsTreeApi):
pass pass
......
...@@ -23,12 +23,19 @@ from ..models import Action ...@@ -23,12 +23,19 @@ from ..models import Action
logger = get_logger(__name__) logger = get_logger(__name__)
__all__ = [ __all__ = [
'UserGrantedAssetsApi', 'UserGrantedNodesApi', 'UserGrantedAssetsApi',
'UserGrantedAssetsAsTreeApi',
'UserGrantedNodeAssetsApi', 'UserGrantedNodeAssetsApi',
'UserGrantedNodesApi',
'UserGrantedNodesAsTreeApi',
'UserGrantedNodesWithAssetsAsTreeApi',
'UserGrantedNodeChildrenApi',
'UserGrantedNodeChildrenAsTreeApi',
'UserGrantedNodeChildrenWithAssetsAsTreeApi',
'RefreshAssetPermissionCacheApi',
'UserGrantedAssetSystemUsersApi',
'ValidateUserAssetPermissionApi', 'ValidateUserAssetPermissionApi',
'UserGrantedNodesWithAssetsAsTreeApi', 'GetUserAssetPermissionActionsApi', 'GetUserAssetPermissionActionsApi',
'RefreshAssetPermissionCacheApi', 'UserGrantedAssetSystemUsersApi',
'UserGrantedNodeChildrenAsTreeApi', 'UserGrantedNodesWithAssetsAsTreeApi',
] ]
...@@ -58,6 +65,66 @@ class UserPermissionMixin: ...@@ -58,6 +65,66 @@ class UserPermissionMixin:
return super().get_permissions() return super().get_permissions()
class UserNodePermissionMixin(UserPermissionMixin):
util = None
def initial(self, *args, **kwargs):
super().initial(*args, *kwargs)
self.util = AssetPermissionUtilV2(self.obj)
class UserNodeTreeMixin:
serializer_class = TreeNodeSerializer
nodes_only_fields = ParserNode.nodes_only_fields
tree = None
def parse_nodes_to_queryset(self, nodes):
nodes = nodes.only(*self.nodes_only_fields)
_queryset = []
tree = self.util.get_user_tree()
for node in nodes:
assets_amount = tree.assets_amount(node.key)
if assets_amount == 0:
continue
node._assets_amount = assets_amount
data = ParserNode.parse_node_to_tree_node(node)
_queryset.append(data)
return _queryset
def get_serializer_queryset(self, queryset):
queryset = self.parse_nodes_to_queryset(queryset)
return queryset
def get_serializer(self, queryset, many=True, **kwargs):
queryset = self.get_serializer_queryset(queryset)
queryset.sort()
return super().get_serializer(queryset, many=many, **kwargs)
class UserAssetTreeMixin:
serializer_class = TreeNodeSerializer
nodes_only_fields = ParserNode.assets_only_fields
@staticmethod
def parse_assets_to_queryset(assets, node):
_queryset = []
for asset in assets:
data = ParserNode.parse_asset_to_tree_node(node, asset)
_queryset.append(data)
return _queryset
def get_serializer_queryset(self, queryset):
queryset = queryset.only(*self.nodes_only_fields)
_queryset = self.parse_assets_to_queryset(queryset, None)
return _queryset
def get_serializer(self, queryset, many=True, **kwargs):
queryset = self.get_serializer_queryset(queryset)
queryset.sort()
return super().get_serializer(queryset, many=many, **kwargs)
class UserGrantedAssetsApi(UserPermissionMixin, ListAPIView): class UserGrantedAssetsApi(UserPermissionMixin, ListAPIView):
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.AssetGrantedSerializer serializer_class = serializers.AssetGrantedSerializer
...@@ -89,6 +156,10 @@ class UserGrantedAssetsApi(UserPermissionMixin, ListAPIView): ...@@ -89,6 +156,10 @@ class UserGrantedAssetsApi(UserPermissionMixin, ListAPIView):
return queryset return queryset
class UserGrantedAssetsAsTreeApi(UserAssetTreeMixin, UserGrantedAssetsApi):
pass
class UserGrantedNodeAssetsApi(UserGrantedAssetsApi): class UserGrantedNodeAssetsApi(UserGrantedAssetsApi):
def get_queryset(self): def get_queryset(self):
node_id = self.kwargs.get("node_id") node_id = self.kwargs.get("node_id")
...@@ -100,18 +171,13 @@ class UserGrantedNodeAssetsApi(UserGrantedAssetsApi): ...@@ -100,18 +171,13 @@ class UserGrantedNodeAssetsApi(UserGrantedAssetsApi):
return queryset return queryset
class UserGrantedNodesApi(UserPermissionMixin, ListAPIView): class UserGrantedNodesApi(UserNodePermissionMixin, ListAPIView):
""" """
查询用户授权的所有节点的API 查询用户授权的所有节点的API
""" """
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.NodeGrantedSerializer serializer_class = serializers.NodeGrantedSerializer
only_fields = NodeSerializer.Meta.only_fields nodes_only_fields = NodeSerializer.Meta.only_fields
util = None
def get(self, request, *args, **kwargs):
self.util = AssetPermissionUtilV2(self.obj)
return super().get(request, *args, **kwargs)
def get_serializer_context(self): def get_serializer_context(self):
context = super().get_serializer_context() context = super().get_serializer_context()
...@@ -120,21 +186,35 @@ class UserGrantedNodesApi(UserPermissionMixin, ListAPIView): ...@@ -120,21 +186,35 @@ class UserGrantedNodesApi(UserPermissionMixin, ListAPIView):
def get_queryset(self): def get_queryset(self):
node_keys = self.util.get_nodes() node_keys = self.util.get_nodes()
queryset = Node.objects.filter(key__in=node_keys) queryset = Node.objects.filter(key__in=node_keys)\
.only(*self.nodes_only_fields)
return queryset return queryset
class UserGrantedNodesAsTreeApi(UserNodeTreeMixin, UserGrantedNodesApi):
pass
class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodesAsTreeApi):
def get_serializer_queryset(self, queryset):
_queryset = super().get_serializer_queryset(queryset)
for node in queryset:
assets = self.util.get_nodes_assets(node)
_queryset.extend(
UserAssetTreeMixin.parse_assets_to_queryset(assets, node)
)
return _queryset
class UserGrantedNodeChildrenApi(UserGrantedNodesApi): class UserGrantedNodeChildrenApi(UserGrantedNodesApi):
node = None node = None
util = None
tree = None tree = None
root_keys = None root_keys = None # 如果是第一次访问,则需要把二级节点添加进去,这个 roots_keys
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
key = self.request.query_params.get("key") key = self.request.query_params.get("key")
pk = self.request.query_params.get("id") pk = self.request.query_params.get("id")
system_user_id = self.request.query_params.get("system_user") system_user_id = self.request.query_params.get("system_user")
self.util = AssetPermissionUtilV2(self.obj)
if system_user_id: if system_user_id:
self.util.filter_permissions(system_users=system_user_id) self.util.filter_permissions(system_users=system_user_id)
self.tree = self.util.get_user_tree() self.tree = self.util.get_user_tree()
...@@ -161,26 +241,16 @@ class UserGrantedNodeChildrenApi(UserGrantedNodesApi): ...@@ -161,26 +241,16 @@ class UserGrantedNodeChildrenApi(UserGrantedNodesApi):
return queryset return queryset
class UserGrantedNodeChildrenAsTreeApi(UserGrantedNodeChildrenApi): class UserGrantedNodeChildrenAsTreeApi(UserNodeTreeMixin, UserGrantedNodeChildrenApi):
serializer_class = TreeNodeSerializer pass
only_fields = ParserNode.nodes_only_fields
def get_queryset(self):
nodes = super().get_queryset()
queryset = []
for node in nodes:
node._assets_amount = self.tree.assets_amount(node.key)
data = ParserNode.parse_node_to_tree_node(node)
queryset.append(data)
return queryset
class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodeChildrenAsTreeApi): class UserGrantedNodeChildrenWithAssetsAsTreeApi(UserGrantedNodeChildrenAsTreeApi):
nodes_only_fields = ParserNode.nodes_only_fields nodes_only_fields = ParserNode.nodes_only_fields
assets_only_fields = ParserNode.assets_only_fields assets_only_fields = ParserNode.assets_only_fields
def get_queryset(self): def get_serializer_queryset(self, queryset):
queryset = super().get_queryset() _queryset = super().get_serializer_queryset(queryset)
nodes = [] nodes = []
if self.node: if self.node:
nodes.append(self.node) nodes.append(self.node)
...@@ -188,12 +258,13 @@ class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodeChildrenAsTreeApi): ...@@ -188,12 +258,13 @@ class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodeChildrenAsTreeApi):
nodes = Node.objects.filter(key__in=self.root_keys) nodes = Node.objects.filter(key__in=self.root_keys)
for node in nodes: for node in nodes:
assets = self.util.get_nodes_assets(node).only(*self.assets_only_fields) assets = self.util.get_nodes_assets(node).only(
for asset in assets: *self.assets_only_fields
data = ParserNode.parse_asset_to_tree_node(node, asset) )
queryset.append(data) _queryset.extend(
queryset = sorted(queryset) UserAssetTreeMixin.parse_assets_to_queryset(assets, node)
return queryset )
return _queryset
class GetUserAssetPermissionActionsApi(RetrieveAPIView): class GetUserAssetPermissionActionsApi(RetrieveAPIView):
......
...@@ -17,16 +17,34 @@ asset_permission_urlpatterns = [ ...@@ -17,16 +17,34 @@ asset_permission_urlpatterns = [
path('users/<uuid:pk>/assets/', api.UserGrantedAssetsApi.as_view(), name='user-assets'), path('users/<uuid:pk>/assets/', api.UserGrantedAssetsApi.as_view(), name='user-assets'),
path('users/assets/', api.UserGrantedAssetsApi.as_view(), name='my-assets'), path('users/assets/', api.UserGrantedAssetsApi.as_view(), name='my-assets'),
# Assets as tree
path('users/<uuid:pk>/assets/tree/', api.UserGrantedAssetsAsTreeApi.as_view(), name='user-assets-as-tree'),
path('users/assets/tree/', api.UserGrantedAssetsAsTreeApi.as_view(), name='my-assets-as-tree'),
# Nodes # Nodes
path('users/<uuid:pk>/nodes/', api.UserGrantedNodesApi.as_view(), name='user-nodes'), path('users/<uuid:pk>/nodes/', api.UserGrantedNodesApi.as_view(), name='user-nodes'),
path('users/nodes/', api.UserGrantedNodesApi.as_view(), name='my-nodes'), path('users/nodes/', api.UserGrantedNodesApi.as_view(), name='my-nodes'),
# Node children
path('users/<uuid:pk>/nodes/children/', api.UserGrantedNodesApi.as_view(), name='user-nodes-children'), path('users/<uuid:pk>/nodes/children/', api.UserGrantedNodesApi.as_view(), name='user-nodes-children'),
path('users/nodes/children/', api.UserGrantedNodesApi.as_view(), name='my-nodes-children'), path('users/nodes/children/', api.UserGrantedNodesApi.as_view(), name='my-nodes-children'),
# Node as tree # Node as tree
path('users/<uuid:pk>/nodes/tree/', api.UserGrantedNodesAsTreeApi.as_view(), name='user-nodes-as-tree'),
path('users/nodes/tree/', api.UserGrantedNodesAsTreeApi.as_view(), name='my-nodes-as-tree'),
# Node with assets as tree
path('users/<uuid:pk>/nodes-with-assets/tree/', api.UserGrantedNodesWithAssetsAsTreeApi.as_view(), name='user-nodes-with-assets-as-tree'),
path('users/nodes-with-assets/tree/', api.UserGrantedNodesWithAssetsAsTreeApi.as_view(), name='my-nodes-with-assets-as-tree'),
# Node children as tree
path('users/<uuid:pk>/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeApi.as_view(), name='user-nodes-children-as-tree'), path('users/<uuid:pk>/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeApi.as_view(), name='user-nodes-children-as-tree'),
path('users/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeApi.as_view(), name='my-nodes-children-as-tree'), path('users/nodes/children/tree/', api.UserGrantedNodeChildrenAsTreeApi.as_view(), name='my-nodes-children-as-tree'),
# Node children with assets as tree
path('users/<uuid:pk>/nodes/children-with-assets/tree/', api.UserGrantedNodeChildrenWithAssetsAsTreeApi.as_view(), name='user-nodes-children-with-assets-as-tree'),
path('users/nodes/children-with-assets/tree/', api.UserGrantedNodeChildrenWithAssetsAsTreeApi.as_view(), name='my-nodes-children-with-assets-as-tree'),
# Node assets # Node assets
path('users/<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGrantedNodeAssetsApi.as_view(), name='user-node-assets'), path('users/<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGrantedNodeAssetsApi.as_view(), name='user-node-assets'),
path('users/nodes/<uuid:node_id>/assets/', api.UserGrantedNodeAssetsApi.as_view(), name='my-node-assets'), path('users/nodes/<uuid:node_id>/assets/', api.UserGrantedNodeAssetsApi.as_view(), name='my-node-assets'),
...@@ -35,10 +53,6 @@ asset_permission_urlpatterns = [ ...@@ -35,10 +53,6 @@ asset_permission_urlpatterns = [
path('users/<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersApi.as_view(), name='user-asset-system-users'), path('users/<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersApi.as_view(), name='user-asset-system-users'),
path('users/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersApi.as_view(), name='my-asset-system-users'), path('users/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersApi.as_view(), name='my-asset-system-users'),
# Node assets as tree
path('users/<uuid:pk>/nodes/children-with-assets/tree/', api.UserGrantedNodesWithAssetsAsTreeApi.as_view(), name='user-nodes-children-with-assets-as-tree'),
path('users/nodes/children-with-assets/tree/', api.UserGrantedNodesWithAssetsAsTreeApi.as_view(), name='my-nodes-children-with-assets-as-tree'),
# 查询某个用户组授权的资产和资产组 # 查询某个用户组授权的资产和资产组
path('user-groups/<uuid:pk>/assets/', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'), path('user-groups/<uuid:pk>/assets/', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'),
path('user-groups/<uuid:pk>/nodes/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'), path('user-groups/<uuid:pk>/nodes/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'),
......
# coding: utf-8 # coding: utf-8
import pickle
import threading
from collections import defaultdict from collections import defaultdict
from functools import reduce from functools import reduce
from django.core.cache import cache
from django.db.models import Q from django.db.models import Q
from django.conf import settings from django.conf import settings
...@@ -12,7 +15,6 @@ from common.tree import TreeNode ...@@ -12,7 +15,6 @@ from common.tree import TreeNode
from assets.utils import TreeService from assets.utils import TreeService
from ..models import AssetPermission from ..models import AssetPermission
from ..hands import Node, Asset, SystemUser from ..hands import Node, Asset, SystemUser
from .. import const
logger = get_logger(__file__) logger = get_logger(__file__)
...@@ -69,9 +71,12 @@ class AssetPermissionUtilV2: ...@@ -69,9 +71,12 @@ class AssetPermissionUtilV2:
'id', 'hostname', 'ip', "platform", "domain_id", 'id', 'hostname', 'ip', "platform", "domain_id",
'comment', 'is_active', 'os', 'org_id' 'comment', 'is_active', 'os', 'org_id'
) )
user_tree_cache_key = 'USER_PERM_TREE_{}'
user_tree_cache_ttl = 3600
def __init__(self, obj, cache_policy='0'): def __init__(self, obj, cache_policy='0'):
self.object = obj self.object = obj
self.cache_policy = cache_policy
self.obj_id = str(obj.id) self.obj_id = str(obj.id)
self._permissions = None self._permissions = None
self._permissions_id = None # 标记_permission的唯一值 self._permissions_id = None # 标记_permission的唯一值
...@@ -84,6 +89,7 @@ class AssetPermissionUtilV2: ...@@ -84,6 +89,7 @@ class AssetPermissionUtilV2:
self._nodes_direct = None self._nodes_direct = None
self._user_tree = None self._user_tree = None
self.full_tree = Node.tree() self.full_tree = Node.tree()
self.mutex = threading.Lock()
@staticmethod @staticmethod
def change_org_if_need(): def change_org_if_need():
...@@ -103,6 +109,31 @@ class AssetPermissionUtilV2: ...@@ -103,6 +109,31 @@ class AssetPermissionUtilV2:
def filter_permissions(self, **filters): def filter_permissions(self, **filters):
self._permissions = self.permissions.filter(**filters) self._permissions = self.permissions.filter(**filters)
@classmethod
def get_user_tree_from_cache(cls, obj_id):
return None
key = cls.user_tree_cache_key.format(obj_id)
data = cache.get(key)
if not data:
return None
user_tree = pickle.loads(data)
return user_tree
@classmethod
def expire_user_tree_cache(cls, obj_id):
if obj_id == 'all':
key = cls.user_tree_cache_key.format('*')
cache.delete_pattern(key)
else:
key = cls.user_tree_cache_key.format(obj_id)
cache.delete(key)
@classmethod
def set_user_tree_to_cache(cls, obj_id, user_tree):
data = pickle.dumps(user_tree)
key = cls.user_tree_cache_key.format(obj_id)
cache.set(key, data, cls.user_tree_cache_ttl)
@property @property
def user_tree(self): def user_tree(self):
return self.get_user_tree() return self.get_user_tree()
...@@ -237,20 +268,26 @@ class AssetPermissionUtilV2: ...@@ -237,20 +268,26 @@ class AssetPermissionUtilV2:
@timeit @timeit
def get_user_tree(self): def get_user_tree(self):
if self._user_tree: with self.mutex:
return self._user_tree if self._user_tree:
user_tree = TreeService() return self._user_tree
full_tree_root = self.full_tree.root_node() print(id(self), self._user_tree)
user_tree.create_node( user_tree = self.__class__.get_user_tree_from_cache(self.obj_id)
tag=full_tree_root.tag, if user_tree:
identifier=full_tree_root.identifier self._user_tree = user_tree
) return user_tree
self.add_direct_nodes_to_user_tree(user_tree) user_tree = TreeService()
self.add_single_assets_node_to_user_tree(user_tree) full_tree_root = self.full_tree.root_node()
self.parse_user_tree_to_full_tree(user_tree) user_tree.create_node(
self.add_empty_node_if_need(user_tree) tag=full_tree_root.tag,
self._user_tree = user_tree identifier=full_tree_root.identifier
return user_tree )
self.add_direct_nodes_to_user_tree(user_tree)
self.add_single_assets_node_to_user_tree(user_tree)
self.parse_user_tree_to_full_tree(user_tree)
self.add_empty_node_if_need(user_tree)
self.__class__.set_user_tree_to_cache(self.obj_id, user_tree)
return user_tree
# Todo: 是否可以获取多个资产的系统用户 # Todo: 是否可以获取多个资产的系统用户
def get_asset_system_users_with_actions(self, asset): def get_asset_system_users_with_actions(self, asset):
...@@ -401,15 +438,17 @@ class ParserNode: ...@@ -401,15 +438,17 @@ class ParserNode:
@staticmethod @staticmethod
def parse_asset_to_tree_node(node, asset): def parse_asset_to_tree_node(node, asset):
icon_skin = 'file' icon_skin = 'file'
if asset.platform.lower() == 'windows': platform = asset.platform.lower()
if platform == 'windows':
icon_skin = 'windows' icon_skin = 'windows'
elif asset.platform.lower() == 'linux': elif platform == 'linux':
icon_skin = 'linux' icon_skin = 'linux'
parent_id = node.key if node else ''
data = { data = {
'id': str(asset.id), 'id': str(asset.id),
'name': asset.hostname, 'name': asset.hostname,
'title': asset.ip, 'title': asset.ip,
'pId': node.key, 'pId': parent_id,
'isParent': False, 'isParent': False,
'open': False, 'open': False,
'iconSkin': icon_skin, 'iconSkin': icon_skin,
......
...@@ -2,20 +2,21 @@ ...@@ -2,20 +2,21 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.urls import path, include from django.urls import path, include, re_path
from rest_framework_bulk.routes import BulkRouter from rest_framework_bulk.routes import BulkRouter
from common import api as capi
from .. import api from .. import api
app_name = 'terminal' app_name = 'terminal'
router = BulkRouter() router = BulkRouter()
router.register(r'sessions', api.SessionViewSet, 'session') router.register(r'sessions', api.SessionViewSet, 'session')
router.register(r'terminal/(?P<terminal>[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status') router.register(r'terminals/(?P<terminal>[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status')
router.register(r'terminal/(?P<terminal>[a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions') router.register(r'terminals/(?P<terminal>[a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions')
router.register(r'terminal', api.TerminalViewSet, 'terminal') router.register(r'terminals', api.TerminalViewSet, 'terminal')
router.register(r'tasks', api.TaskViewSet, 'tasks') router.register(r'tasks', api.TaskViewSet, 'tasks')
router.register(r'command', api.CommandViewSet, 'command') router.register(r'commands', api.CommandViewSet, 'command')
router.register(r'status', api.StatusViewSet, 'status') router.register(r'status', api.StatusViewSet, 'status')
urlpatterns = [ urlpatterns = [
...@@ -23,9 +24,9 @@ urlpatterns = [ ...@@ -23,9 +24,9 @@ urlpatterns = [
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}), api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),
name='session-replay'), name='session-replay'),
path('tasks/kill-session/', api.KillSessionAPI.as_view(), name='kill-session'), path('tasks/kill-session/', api.KillSessionAPI.as_view(), name='kill-session'),
path('terminal/<uuid:terminal>/access-key/', api.TerminalTokenApi.as_view(), path('terminals/<uuid:terminal>/access-key/', api.TerminalTokenApi.as_view(),
name='terminal-access-key'), name='terminal-access-key'),
path('terminal/config/', api.TerminalConfig.as_view(), name='terminal-config'), path('terminals/config/', api.TerminalConfig.as_view(), name='terminal-config'),
path('commands/export/', api.CommandExportApi.as_view(), name="command-export") path('commands/export/', api.CommandExportApi.as_view(), name="command-export")
# v2: get session's replay # v2: get session's replay
# path('v2/sessions/<uuid:pk>/replay/', # path('v2/sessions/<uuid:pk>/replay/',
...@@ -33,7 +34,11 @@ urlpatterns = [ ...@@ -33,7 +34,11 @@ urlpatterns = [
# name='session-replay-v2'), # name='session-replay-v2'),
] ]
urlpatterns += router.urls old_version_urlpatterns = [
re_path('(?P<resource>terminal|command)/.*', capi.redirect_plural_name_api)
]
urlpatterns += router.urls + old_version_urlpatterns
...@@ -2,15 +2,16 @@ ...@@ -2,15 +2,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
from django.urls import path from django.urls import path, re_path
from rest_framework_bulk.routes import BulkRouter from rest_framework_bulk.routes import BulkRouter
from common import api as capi
from .. import api_v2 as api from .. import api_v2 as api
app_name = 'terminal' app_name = 'terminal'
router = BulkRouter() router = BulkRouter()
router.register(r'terminal', api.TerminalViewSet, 'terminal') router.register(r'terminals', api.TerminalViewSet, 'terminal')
urlpatterns = [ urlpatterns = [
...@@ -18,4 +19,8 @@ urlpatterns = [ ...@@ -18,4 +19,8 @@ urlpatterns = [
name='terminal-registration') name='terminal-registration')
] ]
old_version_urlpatterns = [
re_path('(?P<resource>terminal)/.*', capi.redirect_plural_name_api)
]
urlpatterns += router.urls urlpatterns += router.urls
...@@ -108,7 +108,7 @@ function onSelected(event, treeNode) { ...@@ -108,7 +108,7 @@ function onSelected(event, treeNode) {
} }
function initTree() { function initTree(refresh) {
var setting = { var setting = {
view: { view: {
dblClickExpand: false, dblClickExpand: false,
...@@ -131,11 +131,13 @@ function initTree() { ...@@ -131,11 +131,13 @@ function initTree() {
}; };
$.get(treeUrl, function(data, status) { $.get(treeUrl, function(data, status) {
$.fn.zTree.init($("#assetTree"), setting, data); zTree = $.fn.zTree.init($("#assetTree"), setting, data);
zTree = $.fn.zTree.getZTreeObj("assetTree"); if (!refresh) {
initTable();
}
rootNodeAddDom(zTree, function () { rootNodeAddDom(zTree, function () {
treeUrl = setUrlParam(treeUrl, 'cache_policy', '2'); treeUrl = setUrlParam(treeUrl, 'cache_policy', '2');
initTree(); initTree(true);
}); });
}); });
} }
......
...@@ -39,7 +39,6 @@ var systemUsersUrl = "{% url 'api-perms:user-asset-system-users' pk=object.id as ...@@ -39,7 +39,6 @@ var systemUsersUrl = "{% url 'api-perms:user-asset-system-users' pk=object.id as
$(document).ready(function () { $(document).ready(function () {
initTree(); initTree();
initTable();
}); });
</script> </script>
{% endblock %} {% endblock %}
...@@ -42,7 +42,6 @@ var showAssetHref = true; // Need input default true ...@@ -42,7 +42,6 @@ var showAssetHref = true; // Need input default true
$(document).ready(function () { $(document).ready(function () {
initTree(); initTree();
initTable();
}); });
</script> </script>
{% endblock %} {% endblock %}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment