From de43980ee296ab6ce766ea8a0b95d2c110a5fade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=B9=BF?= Date: Sat, 31 Aug 2019 12:07:03 +0800 Subject: [PATCH] Dev beta2 (#3177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Update] 添加loading * [Update] stash * [Update] 修改permission --- .../templates/assets/user_asset_list.html | 1 - apps/assets/urls/api_urls.py | 6 +- apps/assets/utils.py | 64 ++++---- apps/audits/urls/api_urls.py | 10 +- apps/common/api.py | 8 +- apps/perms/api/user_group_permission.py | 7 +- apps/perms/api/user_permission.py | 143 +++++++++++++----- apps/perms/urls/api_urls.py | 22 ++- apps/perms/utils/asset_permission.py | 75 ++++++--- apps/terminal/urls/api_urls.py | 21 ++- apps/terminal/urls/api_urls_v2.py | 9 +- .../templates/users/_granted_assets.html | 10 +- .../templates/users/user_granted_asset.html | 1 - .../users/user_group_granted_asset.html | 1 - 14 files changed, 260 insertions(+), 118 deletions(-) diff --git a/apps/assets/templates/assets/user_asset_list.html b/apps/assets/templates/assets/user_asset_list.html index 1a134cb18..cd268a699 100644 --- a/apps/assets/templates/assets/user_asset_list.html +++ b/apps/assets/templates/assets/user_asset_list.html @@ -34,7 +34,6 @@ var actions = { }}; $(document).ready(function () { initTree(); - initTable(); }).on('click', '.labels li', function () { var val = $(this).text(); $("#user_assets_table_filter input").val(val); diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index 32aa76b37..f748385d8 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -51,15 +51,15 @@ urlpatterns = [ path('system-users//auth-info/', api.SystemUserAuthInfoApi.as_view(), name='system-user-auth-info'), - path('system-users//asset//auth-info/', + path('system-users//assets//auth-info/', api.SystemUserAssetAuthInfoApi.as_view(), name='system-user-asset-auth-info'), path('system-users//assets/', api.SystemUserAssetsListView.as_view(), name='system-user-assets'), path('system-users//push/', api.SystemUserPushApi.as_view(), name='system-user-push'), - path('system-users//asset//push/', + path('system-users//assets//push/', api.SystemUserPushToAssetApi.as_view(), name='system-user-push-to-asset'), - path('system-users//asset//test/', + path('system-users//assets//test/', api.SystemUserTestAssetConnectivityApi.as_view(), name='system-user-test-to-asset'), path('system-users//connective/', api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'), diff --git a/apps/assets/utils.py b/apps/assets/utils.py index 222933f94..b94e84f26 100644 --- a/apps/assets/utils.py +++ b/apps/assets/utils.py @@ -66,27 +66,23 @@ class TreeService(Tree): super().__init__(*args, **kwargs) self.nodes_assets_map = defaultdict(set) self.all_nodes_assets_map = {} - self.mutex = threading.Lock() @classmethod @timeit def new(cls): 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() - set_to_root_org() - all_nodes = Node.objects.all() - origin_org.change_to() - - tree = cls() - tree.create_node(tag='', identifier='') - for node in all_nodes: - tree.create_node( - tag=node.value, identifier=node.key, - parent=node.parent_key, - ) - tree.init_assets_async() + with tmp_to_root_org(): + all_nodes = Node.objects.all() + tree = cls() + tree.create_node(tag='', identifier='') + for node in all_nodes: + tree.create_node( + tag=node.value, identifier=node.key, + parent=node.parent_key, + ) + tree.init_assets() return tree def init_assets_async(self): @@ -95,17 +91,16 @@ class TreeService(Tree): def init_assets(self): from orgs.utils import get_current_org, set_to_root_org - with self.mutex: - origin_org = get_current_org() - set_to_root_org() - queryset = Asset.objects.all().valid().values_list('id', 'nodes__key') + origin_org = get_current_org() + set_to_root_org() + queryset = Asset.objects.all().valid().values_list('id', 'nodes__key') - if origin_org: - origin_org.change_to() - for asset_id, key in queryset: - if not key: - continue - self.nodes_assets_map[key].add(asset_id) + if origin_org: + origin_org.change_to() + for asset_id, key in queryset: + if not key: + continue + self.nodes_assets_map[key].add(asset_id) def all_children(self, nid, with_self=True, deep=False): children_ids = self.expand_tree(nid) @@ -146,13 +141,11 @@ class TreeService(Tree): return parent def assets(self, nid): - with self.mutex: - assets = self.nodes_assets_map[nid] - return assets + assets = self.nodes_assets_map[nid] + return 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): assets = self.all_nodes_assets_map.get(nid) @@ -186,12 +179,17 @@ class TreeService(Tree): self.safe_add_ancestors(ancestors) parent = self.get_node(parent_id) - print("Add node: {} {}".format(node.identifier, parent.identifier)) # 如果当前节点已再树中,则移动当前节点到父节点中 # 这个是由于 当前节点放到了二级节点中 if self.contains(node.identifier): self.move_node(node.identifier, parent.identifier) else: 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() diff --git a/apps/audits/urls/api_urls.py b/apps/audits/urls/api_urls.py index 4413eafad..249843f24 100644 --- a/apps/audits/urls/api_urls.py +++ b/apps/audits/urls/api_urls.py @@ -1,17 +1,23 @@ # ~*~ coding: utf-8 ~*~ 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 common import api as capi from .. import api app_name = "audits" router = DefaultRouter() -router.register(r'ftp-log', api.FTPLogViewSet, 'ftp-log') +router.register(r'ftp-logs', api.FTPLogViewSet, 'ftp-log') urlpatterns = [ ] +old_version_urlpatterns = [ + re_path('(?Pftp-log)/.*', capi.redirect_plural_name_api) +] + urlpatterns += router.urls diff --git a/apps/common/api.py b/apps/common/api.py index a3b1938be..d69540cfd 100644 --- a/apps/common/api.py +++ b/apps/common/api.py @@ -12,11 +12,14 @@ from rest_framework import generics, serializers from .http import HttpResponseTemporaryRedirect from .const import KEY_CACHE_RESOURCES_ID +from .utils import get_logger __all__ = [ 'LogTailApi', 'ResourcesIDCacheApi', ] +logger = get_logger(__file__) + class OutputSerializer(serializers.Serializer): output = serializers.CharField() @@ -93,6 +96,7 @@ class ResourcesIDCacheApi(APIView): @csrf_exempt def redirect_plural_name_api(request, *args, **kwargs): resource = kwargs.get("resource", "") - full_path = request.get_full_path() - full_path = full_path.replace(resource, resource+"s", 1) + org_full_path = request.get_full_path() + full_path = org_full_path.replace(resource, resource+"s", 1) + logger.debug("Redirect {} => {}".format(org_full_path, full_path)) return HttpResponseTemporaryRedirect(full_path) diff --git a/apps/perms/api/user_group_permission.py b/apps/perms/api/user_group_permission.py index 785b11927..7d93724c3 100644 --- a/apps/perms/api/user_group_permission.py +++ b/apps/perms/api/user_group_permission.py @@ -10,9 +10,10 @@ from . import user_permission as uapi __all__ = [ 'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi', 'UserGroupGrantedNodeAssetsApi', 'UserGroupGrantedNodeChildrenApi', - 'UserGroupGrantedNodeChildrenAsTreeApi', 'UserGroupGrantedNodesWithAssetsAsTreeApi', + 'UserGroupGrantedNodeChildrenAsTreeApi', + 'UserGroupGrantedNodeChildrenWithAssetsAsTreeApi', 'UserGroupGrantedAssetSystemUsersApi', - # 'UserGroupGrantedNodesWithAssetsAsTreeApi', + # 'UserGroupGrantedNodeChildrenWithAssetsAsTreeApi', ] @@ -45,7 +46,7 @@ class UserGroupGrantedNodeChildrenAsTreeApi(UserGroupPermissionMixin, uapi.UserG pass -class UserGroupGrantedNodesWithAssetsAsTreeApi(UserGroupPermissionMixin, uapi.UserGrantedNodesWithAssetsAsTreeApi): +class UserGroupGrantedNodeChildrenWithAssetsAsTreeApi(UserGroupPermissionMixin, uapi.UserGrantedNodeChildrenWithAssetsAsTreeApi): pass diff --git a/apps/perms/api/user_permission.py b/apps/perms/api/user_permission.py index f965f8ec4..f19fc56d8 100644 --- a/apps/perms/api/user_permission.py +++ b/apps/perms/api/user_permission.py @@ -23,12 +23,19 @@ from ..models import Action logger = get_logger(__name__) __all__ = [ - 'UserGrantedAssetsApi', 'UserGrantedNodesApi', + 'UserGrantedAssetsApi', + 'UserGrantedAssetsAsTreeApi', 'UserGrantedNodeAssetsApi', + 'UserGrantedNodesApi', + 'UserGrantedNodesAsTreeApi', + 'UserGrantedNodesWithAssetsAsTreeApi', + 'UserGrantedNodeChildrenApi', + 'UserGrantedNodeChildrenAsTreeApi', + 'UserGrantedNodeChildrenWithAssetsAsTreeApi', + 'RefreshAssetPermissionCacheApi', + 'UserGrantedAssetSystemUsersApi', 'ValidateUserAssetPermissionApi', - 'UserGrantedNodesWithAssetsAsTreeApi', 'GetUserAssetPermissionActionsApi', - 'RefreshAssetPermissionCacheApi', 'UserGrantedAssetSystemUsersApi', - 'UserGrantedNodeChildrenAsTreeApi', 'UserGrantedNodesWithAssetsAsTreeApi', + 'GetUserAssetPermissionActionsApi', ] @@ -58,6 +65,66 @@ class UserPermissionMixin: 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): permission_classes = (IsOrgAdminOrAppUser,) serializer_class = serializers.AssetGrantedSerializer @@ -89,6 +156,10 @@ class UserGrantedAssetsApi(UserPermissionMixin, ListAPIView): return queryset +class UserGrantedAssetsAsTreeApi(UserAssetTreeMixin, UserGrantedAssetsApi): + pass + + class UserGrantedNodeAssetsApi(UserGrantedAssetsApi): def get_queryset(self): node_id = self.kwargs.get("node_id") @@ -100,18 +171,13 @@ class UserGrantedNodeAssetsApi(UserGrantedAssetsApi): return queryset -class UserGrantedNodesApi(UserPermissionMixin, ListAPIView): +class UserGrantedNodesApi(UserNodePermissionMixin, ListAPIView): """ 查询用户授权的所有节点的API """ permission_classes = (IsOrgAdminOrAppUser,) serializer_class = serializers.NodeGrantedSerializer - 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) + nodes_only_fields = NodeSerializer.Meta.only_fields def get_serializer_context(self): context = super().get_serializer_context() @@ -120,21 +186,35 @@ class UserGrantedNodesApi(UserPermissionMixin, ListAPIView): def get_queryset(self): 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 +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): node = None - util = None tree = None - root_keys = None + root_keys = None # 如果是第一次访问,则需要把二级节点添加进去,这个 roots_keys def get(self, request, *args, **kwargs): key = self.request.query_params.get("key") pk = self.request.query_params.get("id") system_user_id = self.request.query_params.get("system_user") - self.util = AssetPermissionUtilV2(self.obj) if system_user_id: self.util.filter_permissions(system_users=system_user_id) self.tree = self.util.get_user_tree() @@ -161,26 +241,16 @@ class UserGrantedNodeChildrenApi(UserGrantedNodesApi): return queryset -class UserGrantedNodeChildrenAsTreeApi(UserGrantedNodeChildrenApi): - serializer_class = TreeNodeSerializer - 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 UserGrantedNodeChildrenAsTreeApi(UserNodeTreeMixin, UserGrantedNodeChildrenApi): + pass -class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodeChildrenAsTreeApi): +class UserGrantedNodeChildrenWithAssetsAsTreeApi(UserGrantedNodeChildrenAsTreeApi): nodes_only_fields = ParserNode.nodes_only_fields assets_only_fields = ParserNode.assets_only_fields - def get_queryset(self): - queryset = super().get_queryset() + def get_serializer_queryset(self, queryset): + _queryset = super().get_serializer_queryset(queryset) nodes = [] if self.node: nodes.append(self.node) @@ -188,12 +258,13 @@ class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodeChildrenAsTreeApi): nodes = Node.objects.filter(key__in=self.root_keys) for node in nodes: - assets = self.util.get_nodes_assets(node).only(*self.assets_only_fields) - for asset in assets: - data = ParserNode.parse_asset_to_tree_node(node, asset) - queryset.append(data) - queryset = sorted(queryset) - return queryset + assets = self.util.get_nodes_assets(node).only( + *self.assets_only_fields + ) + _queryset.extend( + UserAssetTreeMixin.parse_assets_to_queryset(assets, node) + ) + return _queryset class GetUserAssetPermissionActionsApi(RetrieveAPIView): diff --git a/apps/perms/urls/api_urls.py b/apps/perms/urls/api_urls.py index 636da3271..7b1336a6b 100644 --- a/apps/perms/urls/api_urls.py +++ b/apps/perms/urls/api_urls.py @@ -17,16 +17,34 @@ asset_permission_urlpatterns = [ path('users//assets/', api.UserGrantedAssetsApi.as_view(), name='user-assets'), path('users/assets/', api.UserGrantedAssetsApi.as_view(), name='my-assets'), + # Assets as tree + path('users//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 path('users//nodes/', api.UserGrantedNodesApi.as_view(), name='user-nodes'), path('users/nodes/', api.UserGrantedNodesApi.as_view(), name='my-nodes'), + + # Node children path('users//nodes/children/', api.UserGrantedNodesApi.as_view(), name='user-nodes-children'), path('users/nodes/children/', api.UserGrantedNodesApi.as_view(), name='my-nodes-children'), # Node as tree + path('users//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//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//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'), + # Node children with assets as tree + path('users//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 path('users//nodes//assets/', api.UserGrantedNodeAssetsApi.as_view(), name='user-node-assets'), path('users/nodes//assets/', api.UserGrantedNodeAssetsApi.as_view(), name='my-node-assets'), @@ -35,10 +53,6 @@ asset_permission_urlpatterns = [ path('users//assets//system-users/', api.UserGrantedAssetSystemUsersApi.as_view(), name='user-asset-system-users'), path('users/assets//system-users/', api.UserGrantedAssetSystemUsersApi.as_view(), name='my-asset-system-users'), - # Node assets as tree - path('users//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//assets/', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'), path('user-groups//nodes/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'), diff --git a/apps/perms/utils/asset_permission.py b/apps/perms/utils/asset_permission.py index 3f7874753..bf1842c57 100644 --- a/apps/perms/utils/asset_permission.py +++ b/apps/perms/utils/asset_permission.py @@ -1,8 +1,11 @@ # coding: utf-8 +import pickle +import threading from collections import defaultdict from functools import reduce +from django.core.cache import cache from django.db.models import Q from django.conf import settings @@ -12,7 +15,6 @@ from common.tree import TreeNode from assets.utils import TreeService from ..models import AssetPermission from ..hands import Node, Asset, SystemUser -from .. import const logger = get_logger(__file__) @@ -69,9 +71,12 @@ class AssetPermissionUtilV2: 'id', 'hostname', 'ip', "platform", "domain_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'): self.object = obj + self.cache_policy = cache_policy self.obj_id = str(obj.id) self._permissions = None self._permissions_id = None # 标记_permission的唯一值 @@ -84,6 +89,7 @@ class AssetPermissionUtilV2: self._nodes_direct = None self._user_tree = None self.full_tree = Node.tree() + self.mutex = threading.Lock() @staticmethod def change_org_if_need(): @@ -103,6 +109,31 @@ class AssetPermissionUtilV2: def filter_permissions(self, **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 def user_tree(self): return self.get_user_tree() @@ -237,20 +268,26 @@ class AssetPermissionUtilV2: @timeit def get_user_tree(self): - if self._user_tree: - return self._user_tree - user_tree = TreeService() - full_tree_root = self.full_tree.root_node() - user_tree.create_node( - tag=full_tree_root.tag, - identifier=full_tree_root.identifier - ) - 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._user_tree = user_tree - return user_tree + with self.mutex: + if self._user_tree: + return self._user_tree + print(id(self), self._user_tree) + user_tree = self.__class__.get_user_tree_from_cache(self.obj_id) + if user_tree: + self._user_tree = user_tree + return user_tree + user_tree = TreeService() + full_tree_root = self.full_tree.root_node() + user_tree.create_node( + tag=full_tree_root.tag, + identifier=full_tree_root.identifier + ) + 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: 是否可以获取多个资产的系统用户 def get_asset_system_users_with_actions(self, asset): @@ -401,15 +438,17 @@ class ParserNode: @staticmethod def parse_asset_to_tree_node(node, asset): icon_skin = 'file' - if asset.platform.lower() == 'windows': + platform = asset.platform.lower() + if platform == 'windows': icon_skin = 'windows' - elif asset.platform.lower() == 'linux': + elif platform == 'linux': icon_skin = 'linux' + parent_id = node.key if node else '' data = { 'id': str(asset.id), 'name': asset.hostname, 'title': asset.ip, - 'pId': node.key, + 'pId': parent_id, 'isParent': False, 'open': False, 'iconSkin': icon_skin, diff --git a/apps/terminal/urls/api_urls.py b/apps/terminal/urls/api_urls.py index 95ccc85e2..96db7d31f 100644 --- a/apps/terminal/urls/api_urls.py +++ b/apps/terminal/urls/api_urls.py @@ -2,20 +2,21 @@ # -*- 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 common import api as capi from .. import api app_name = 'terminal' router = BulkRouter() router.register(r'sessions', api.SessionViewSet, 'session') -router.register(r'terminal/(?P[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status') -router.register(r'terminal/(?P[a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions') -router.register(r'terminal', api.TerminalViewSet, 'terminal') +router.register(r'terminals/(?P[a-zA-Z0-9\-]{36})?/?status', api.StatusViewSet, 'terminal-status') +router.register(r'terminals/(?P[a-zA-Z0-9\-]{36})?/?sessions', api.SessionViewSet, 'terminal-sessions') +router.register(r'terminals', api.TerminalViewSet, 'terminal') 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') urlpatterns = [ @@ -23,9 +24,9 @@ urlpatterns = [ api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}), name='session-replay'), path('tasks/kill-session/', api.KillSessionAPI.as_view(), name='kill-session'), - path('terminal//access-key/', api.TerminalTokenApi.as_view(), + path('terminals//access-key/', api.TerminalTokenApi.as_view(), 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") # v2: get session's replay # path('v2/sessions//replay/', @@ -33,7 +34,11 @@ urlpatterns = [ # name='session-replay-v2'), ] -urlpatterns += router.urls +old_version_urlpatterns = [ + re_path('(?Pterminal|command)/.*', capi.redirect_plural_name_api) +] + +urlpatterns += router.urls + old_version_urlpatterns diff --git a/apps/terminal/urls/api_urls_v2.py b/apps/terminal/urls/api_urls_v2.py index e03e69c28..42c9ffdb5 100644 --- a/apps/terminal/urls/api_urls_v2.py +++ b/apps/terminal/urls/api_urls_v2.py @@ -2,15 +2,16 @@ # -*- coding: utf-8 -*- # -from django.urls import path +from django.urls import path, re_path from rest_framework_bulk.routes import BulkRouter +from common import api as capi from .. import api_v2 as api app_name = 'terminal' router = BulkRouter() -router.register(r'terminal', api.TerminalViewSet, 'terminal') +router.register(r'terminals', api.TerminalViewSet, 'terminal') urlpatterns = [ @@ -18,4 +19,8 @@ urlpatterns = [ name='terminal-registration') ] +old_version_urlpatterns = [ + re_path('(?Pterminal)/.*', capi.redirect_plural_name_api) +] + urlpatterns += router.urls diff --git a/apps/users/templates/users/_granted_assets.html b/apps/users/templates/users/_granted_assets.html index 7904af4fb..173aec607 100644 --- a/apps/users/templates/users/_granted_assets.html +++ b/apps/users/templates/users/_granted_assets.html @@ -108,7 +108,7 @@ function onSelected(event, treeNode) { } -function initTree() { +function initTree(refresh) { var setting = { view: { dblClickExpand: false, @@ -131,11 +131,13 @@ function initTree() { }; $.get(treeUrl, function(data, status) { - $.fn.zTree.init($("#assetTree"), setting, data); - zTree = $.fn.zTree.getZTreeObj("assetTree"); + zTree = $.fn.zTree.init($("#assetTree"), setting, data); + if (!refresh) { + initTable(); + } rootNodeAddDom(zTree, function () { treeUrl = setUrlParam(treeUrl, 'cache_policy', '2'); - initTree(); + initTree(true); }); }); } diff --git a/apps/users/templates/users/user_granted_asset.html b/apps/users/templates/users/user_granted_asset.html index 0ad948a18..d70418081 100644 --- a/apps/users/templates/users/user_granted_asset.html +++ b/apps/users/templates/users/user_granted_asset.html @@ -39,7 +39,6 @@ var systemUsersUrl = "{% url 'api-perms:user-asset-system-users' pk=object.id as $(document).ready(function () { initTree(); - initTable(); }); {% endblock %} diff --git a/apps/users/templates/users/user_group_granted_asset.html b/apps/users/templates/users/user_group_granted_asset.html index 23fc98436..9b35f7daf 100644 --- a/apps/users/templates/users/user_group_granted_asset.html +++ b/apps/users/templates/users/user_group_granted_asset.html @@ -42,7 +42,6 @@ var showAssetHref = true; // Need input default true $(document).ready(function () { initTree(); - initTable(); }); {% endblock %}