diff --git a/apps/assets/api/asset.py b/apps/assets/api/asset.py
index 140981263..bc7aa0409 100644
--- a/apps/assets/api/asset.py
+++ b/apps/assets/api/asset.py
@@ -62,7 +62,7 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
queryset = queryset.filter(cluster__in=clusters)
if node_id:
node = get_object_or_404(Node, id=node_id)
- queryset = queryset.filter(nodes__key__startswith=node.key)
+ queryset = queryset.filter(nodes__key__startswith=node.key).distinct()
return queryset
diff --git a/apps/assets/api/tree.py b/apps/assets/api/tree.py
index 02bb555f3..a5f9fff8a 100644
--- a/apps/assets/api/tree.py
+++ b/apps/assets/api/tree.py
@@ -14,6 +14,7 @@
# limitations under the License.
from rest_framework import generics, mixins
+from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet
from django.utils.translation import ugettext_lazy as _
@@ -25,7 +26,10 @@ from .. import serializers
logger = get_logger(__file__)
-__all__ = ['NodeViewSet', 'NodeChildrenApi']
+__all__ = [
+ 'NodeViewSet', 'NodeChildrenApi',
+ 'NodeAddAssetsApi', 'NodeRemoveAssetsApi',
+]
class NodeViewSet(BulkModelViewSet):
@@ -70,3 +74,26 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
response = [{"id": node.id, "key": node.key, "value": node.value} for node in children]
return Response(response, status=200)
+
+class NodeAddAssetsApi(generics.UpdateAPIView):
+ serializer_class = serializers.NodeAssetsSerializer
+ queryset = Node.objects.all()
+ permission_classes = (IsSuperUser,)
+ instance = None
+
+ def perform_update(self, serializer):
+ assets = serializer.validated_data.get('assets')
+ instance = self.get_object()
+ instance.assets.add(*tuple(assets))
+
+
+class NodeRemoveAssetsApi(generics.UpdateAPIView):
+ serializer_class = serializers.NodeAssetsSerializer
+ queryset = Node.objects.all()
+ permission_classes = (IsSuperUser,)
+ instance = None
+
+ def perform_update(self, serializer):
+ assets = serializer.validated_data.get('assets')
+ instance = self.get_object()
+ instance.assets.remove(*tuple(assets))
diff --git a/apps/assets/serializers.py b/apps/assets/serializers.py
index 4eb05b187..b7cc0ee9a 100644
--- a/apps/assets/serializers.py
+++ b/apps/assets/serializers.py
@@ -335,3 +335,11 @@ class NodeSerializer(serializers.ModelSerializer):
field = fields["key"]
field.required = False
return fields
+
+
+class NodeAssetsSerializer(serializers.ModelSerializer):
+ assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
+
+ class Meta:
+ model = Node
+ fields = ['assets']
diff --git a/apps/assets/templates/assets/_asset_list_modal.html b/apps/assets/templates/assets/_asset_list_modal.html
index 3b9f8d136..b68ab0378 100644
--- a/apps/assets/templates/assets/_asset_list_modal.html
+++ b/apps/assets/templates/assets/_asset_list_modal.html
@@ -109,7 +109,20 @@ $(document).ready(function(){
return
}
+ var data = {
+ 'assets': id_list
+ };
+ var success = function () {
+ modal_table.ajax.reload()
+ };
+
+ APIUpdateAttr({
+ 'url': '/api/assets/v1/nodes/' + current_node.id + '/assets/add/',
+ 'method': 'PUT',
+ 'body': JSON.stringify(data),
+ 'success': success
+ })
})
diff --git a/apps/assets/templates/assets/tree.html b/apps/assets/templates/assets/tree.html
index dcbb6bec9..b6c33965a 100644
--- a/apps/assets/templates/assets/tree.html
+++ b/apps/assets/templates/assets/tree.html
@@ -88,6 +88,7 @@
@@ -169,8 +170,6 @@ function initTable() {
}
-
-
function addTreeNode() {
hideRMenu();
var parentNode = zTree.getSelectedNodes()[0];
@@ -281,17 +280,26 @@ function onRename(event, treeId, treeNode, isCancel){
function onSelected(event, treeNode) {
var url = asset_table.ajax.url();
url = setUrlParam(url, "node_id", treeNode.id);
+ setCookie('node_selected', treeNode.id);
asset_table.ajax.url(url);
asset_table.ajax.reload();
}
function selectQueryNode() {
- var node_id = $.getUrlParam("node");
- if (node_id !== null) {
- var node = zTree.getNodesByParam("id", node_id, null);
- if (node){
- zTree.selectNode(node[0]);
- }
+ var query_node_id = $.getUrlParam("node");
+ var cookie_node_id = getCookie('node_selected');
+ var node;
+ var node_id;
+
+ if (query_node_id !== null) {
+ node_id = query_node_id
+ } else if (cookie_node_id !== null) {
+ node_id = cookie_node_id;
+ }
+
+ node = zTree.getNodesByParam("id", node_id, null);
+ if (node){
+ zTree.selectNode(node[0]);
}
}
@@ -479,6 +487,31 @@ $(document).ready(function(){
var url = "{% url 'assets:asset-bulk-update' %}?assets_id=" + id_list_string;
location.href = url
}
+
+ function doRemove() {
+ var current_node;
+ var nodes = zTree.getSelectedNodes();
+ if (nodes && nodes.length === 1) {
+ current_node = nodes[0]
+ } else {
+ return
+ }
+
+ var data = {
+ 'assets': id_list
+ };
+
+ var success = function () {
+ asset_table.ajax.reload()
+ };
+
+ APIUpdateAttr({
+ 'url': '/api/assets/v1/nodes/' + current_node.id + '/assets/remove/',
+ 'method': 'PUT',
+ 'body': JSON.stringify(data),
+ 'success': success
+ })
+ }
switch(action) {
case 'deactive':
doDeactive();
@@ -492,6 +525,9 @@ $(document).ready(function(){
case 'active':
doActive();
break;
+ case 'remove':
+ doRemove();
+ break;
default:
break;
}
diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py
index 43e8aa711..0e14cda21 100644
--- a/apps/assets/urls/api_urls.py
+++ b/apps/assets/urls/api_urls.py
@@ -44,6 +44,8 @@ urlpatterns = [
url(r'^v1/system-user/(?P[0-9a-zA-Z\-]{36})/connective/$',
api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'),
url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/children/$', api.NodeChildrenApi.as_view(), name='node-children'),
+ url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/assets/add/$', api.NodeAddAssetsApi.as_view(), name='node-add-assets'),
+ url(r'^v1/nodes/(?P[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'),
]
urlpatterns += router.urls
diff --git a/apps/perms/templates/perms/asset_permission_list.html b/apps/perms/templates/perms/asset_permission_list.html
index 257dcaf20..9f8e26a43 100644
--- a/apps/perms/templates/perms/asset_permission_list.html
+++ b/apps/perms/templates/perms/asset_permission_list.html
@@ -135,17 +135,26 @@ function initTable() {
function onSelected(event, treeNode) {
var url = table.ajax.url();
url = setUrlParam(url, "node_id", treeNode.id);
+ setCookie('node_selected', treeNode.id);
table.ajax.url(url);
table.ajax.reload();
}
function selectQueryNode() {
- var node_id = $.getUrlParam("node");
- if (node_id !== null) {
- var node = zTree.getNodesByParam("id", node_id, null);
- if (node) {
- zTree.selectNode(node[0]);
- }
+ var query_node_id = $.getUrlParam("node");
+ var cookie_node_id = getCookie('node_selected');
+ var node;
+ var node_id;
+
+ if (query_node_id !== null) {
+ node_id = query_node_id
+ } else if (cookie_node_id !== null) {
+ node_id = cookie_node_id;
+ }
+
+ node = zTree.getNodesByParam("id", node_id, null);
+ if (node){
+ zTree.selectNode(node[0]);
}
}
diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js
index eee1720c0..178836058 100644
--- a/apps/static/js/jumpserver.js
+++ b/apps/static/js/jumpserver.js
@@ -562,7 +562,6 @@ function setUrlParam(url, name, value) {
url = urlArray[0] + "?";
var newParam = [];
$.each(oriParamMap, function (index, value) {
- console.log(index, value);
newParam.push(index + "=" + value);
});
url += newParam.join("&")