Commit dbdcdb72 authored by ibuler's avatar ibuler

Merge branch 'dev' of github.com:jumpserver/jumpserver into dev

parents 1ff9f0ea 517a27ea
...@@ -41,40 +41,46 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet): ...@@ -41,40 +41,46 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
pagination_class = LimitOffsetPagination pagination_class = LimitOffsetPagination
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
def filter_node(self): def filter_node(self, queryset):
node_id = self.request.query_params.get("node_id") node_id = self.request.query_params.get("node_id")
if not node_id: if not node_id:
return return queryset
node = get_object_or_404(Node, id=node_id) node = get_object_or_404(Node, id=node_id)
show_current_asset = self.request.query_params.get("show_current_asset") in ('1', 'true') show_current_asset = self.request.query_params.get("show_current_asset") in ('1', 'true')
if node.is_root(): if node.is_root() and show_current_asset:
if show_current_asset: queryset = queryset.filter(
self.queryset = self.queryset.filter( Q(nodes=node_id) | Q(nodes__isnull=True)
Q(nodes=node_id) | Q(nodes__isnull=True) )
) elif node.is_root() and not show_current_asset:
return pass
if show_current_asset: elif not node.is_root() and show_current_asset:
self.queryset = self.queryset.filter(nodes=node) queryset = queryset.filter(nodes=node)
else: else:
self.queryset = self.queryset.filter( queryset = queryset.filter(
nodes__key__regex='^{}(:[0-9]+)*$'.format(node.key), nodes__key__regex='^{}(:[0-9]+)*$'.format(node.key),
) )
return queryset
def filter_admin_user_id(self): def filter_admin_user_id(self, queryset):
admin_user_id = self.request.query_params.get('admin_user_id') admin_user_id = self.request.query_params.get('admin_user_id')
if admin_user_id: if not admin_user_id:
admin_user = get_object_or_404(AdminUser, id=admin_user_id) return queryset
self.queryset = self.queryset.filter(admin_user=admin_user) admin_user = get_object_or_404(AdminUser, id=admin_user_id)
queryset = queryset.filter(admin_user=admin_user)
return queryset
def filter_queryset(self, queryset):
queryset = super().filter_queryset(queryset)
queryset = self.filter_node(queryset)
queryset = self.filter_admin_user_id(queryset)
return queryset
def get_queryset(self): def get_queryset(self):
self.queryset = super().get_queryset()\ queryset = super().get_queryset().distinct()
.prefetch_related('labels', 'nodes')\ queryset = self.get_serializer_class().setup_eager_loading(queryset)
.select_related('admin_user') return queryset
self.filter_admin_user_id()
self.filter_node()
return self.queryset.distinct()
class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView): class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
......
...@@ -17,13 +17,13 @@ from rest_framework import generics, mixins, viewsets ...@@ -17,13 +17,13 @@ from rest_framework import generics, mixins, viewsets
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from common.utils import get_logger, get_object_or_none from common.utils import get_logger, get_object_or_none
from common.tree import TreeNodeSerializer
from ..hands import IsOrgAdmin from ..hands import IsOrgAdmin
from ..models import Node, Asset from ..models import Node
from ..tasks import update_assets_hardware_info_util, test_asset_connectability_util from ..tasks import update_assets_hardware_info_util, test_asset_connectability_util
from .. import serializers from .. import serializers
...@@ -33,7 +33,8 @@ __all__ = [ ...@@ -33,7 +33,8 @@ __all__ = [
'NodeViewSet', 'NodeChildrenApi', 'NodeAssetsApi', 'NodeViewSet', 'NodeChildrenApi', 'NodeAssetsApi',
'NodeAddAssetsApi', 'NodeRemoveAssetsApi', 'NodeReplaceAssetsApi', 'NodeAddAssetsApi', 'NodeRemoveAssetsApi', 'NodeReplaceAssetsApi',
'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi', 'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi',
'TestNodeConnectiveApi' 'TestNodeConnectiveApi', 'NodeListAsTreeApi',
'NodeChildrenAsTreeApi',
] ]
...@@ -42,22 +43,89 @@ class NodeViewSet(viewsets.ModelViewSet): ...@@ -42,22 +43,89 @@ class NodeViewSet(viewsets.ModelViewSet):
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
serializer_class = serializers.NodeSerializer serializer_class = serializers.NodeSerializer
def perform_create(self, serializer):
child_key = Node.root().get_next_child_key()
serializer.validated_data["key"] = child_key
serializer.save()
def update(self, request, *args, **kwargs): class NodeListAsTreeApi(generics.ListAPIView):
node = self.get_object() """
if node.is_root(): 获取节点列表树
node_value = node.value [
post_value = request.data.get('value') {
if node_value != post_value: "id": "",
return Response( "name": "",
{"msg": _("You can't update the root node name")}, "pId": "",
status=400 "meta": ""
) }
return super().update(request, *args, **kwargs) ]
"""
permission_classes = (IsOrgAdmin,)
serializer_class = TreeNodeSerializer
def get_queryset(self):
queryset = [node.as_tree_node() for node in Node.objects.all()]
return queryset
def filter_queryset(self, queryset):
if self.request.query_params.get('refresh', '0') == '1':
queryset = self.refresh_nodes(queryset)
return queryset
@staticmethod
def refresh_nodes(queryset):
Node.expire_nodes_assets_amount()
Node.expire_nodes_full_value()
return queryset
class NodeChildrenAsTreeApi(generics.ListAPIView):
"""
节点子节点作为树返回,
[
{
"id": "",
"name": "",
"pId": "",
"meta": ""
}
]
"""
permission_classes = (IsOrgAdmin,)
serializer_class = TreeNodeSerializer
node = None
is_root = False
def get_queryset(self):
node_key = self.request.query_params.get('key')
if node_key:
self.node = Node.objects.get(key=node_key)
queryset = self.node.get_children(with_self=False)
else:
self.is_root = True
self.node = Node.root()
queryset = list(self.node.get_children(with_self=True))
nodes_invalid = Node.objects.exclude(key__startswith=self.node.key)
queryset.extend(list(nodes_invalid))
queryset = [node.as_tree_node() for node in queryset]
return queryset
def filter_assets(self, queryset):
include_assets = self.request.query_params.get('assets', '0') == '1'
if not include_assets:
return queryset
assets = self.node.get_assets()
for asset in assets:
queryset.append(asset.as_tree_node(self.node))
return queryset
def filter_queryset(self, queryset):
queryset = self.filter_assets(queryset)
queryset = self.filter_refresh_nodes(queryset)
return queryset
def filter_refresh_nodes(self, queryset):
if self.request.query_params.get('refresh', '0') == '1':
Node.expire_nodes_assets_amount()
Node.expire_nodes_full_value()
return queryset
class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
...@@ -66,19 +134,10 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): ...@@ -66,19 +134,10 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
serializer_class = serializers.NodeSerializer serializer_class = serializers.NodeSerializer
instance = None instance = None
def counter(self):
values = [
child.value[child.value.rfind(' '):]
for child in self.get_object().get_children()
if child.value.startswith("新节点 ")
]
values = [int(value) for value in values if value.strip().isdigit()]
count = max(values)+1 if values else 1
return count
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
instance = self.get_object()
if not request.data.get("value"): if not request.data.get("value"):
request.data["value"] = _("New node {}").format(self.counter()) request.data["value"] = instance.get_next_child_preset_name()
return super().post(request, *args, **kwargs) return super().post(request, *args, **kwargs)
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):
...@@ -90,10 +149,7 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): ...@@ -90,10 +149,7 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
'The same level node name cannot be the same' 'The same level node name cannot be the same'
) )
node = instance.create_child(value=value) node = instance.create_child(value=value)
return Response( return Response(self.serializer_class(instance=node).data, status=201)
{"id": node.id, "key": node.key, "value": node.value},
status=201,
)
def get_object(self): def get_object(self):
pk = self.kwargs.get('pk') or self.request.query_params.get('id') pk = self.kwargs.get('pk') or self.request.query_params.get('id')
...@@ -106,7 +162,6 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): ...@@ -106,7 +162,6 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
def get_queryset(self): def get_queryset(self):
queryset = [] queryset = []
query_all = self.request.query_params.get("all") query_all = self.request.query_params.get("all")
query_assets = self.request.query_params.get('assets')
node = self.get_object() node = self.get_object()
if node is None: if node is None:
...@@ -119,23 +174,8 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView): ...@@ -119,23 +174,8 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
else: else:
children = node.get_children() children = node.get_children()
queryset.extend(list(children)) queryset.extend(list(children))
if query_assets:
assets = node.get_assets()
for asset in assets:
node_fake = Node()
node_fake.assets__count = 0
node_fake.id = asset.id
node_fake.is_node = False
node_fake.key = node.key + ':0'
node_fake.value = asset.hostname
queryset.append(node_fake)
queryset = sorted(queryset, key=lambda x: x.is_node, reverse=True)
return queryset return queryset
def get(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
class NodeAssetsApi(generics.ListAPIView): class NodeAssetsApi(generics.ListAPIView):
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
......
...@@ -255,6 +255,36 @@ class Asset(OrgModelMixin): ...@@ -255,6 +255,36 @@ class Asset(OrgModelMixin):
}) })
return data return data
def as_tree_node(self, parent_node):
from common.tree import TreeNode
icon_skin = 'file'
if self.platform.lower() == 'windows':
icon_skin = 'windows'
elif self.platform.lower() == 'linux':
icon_skin = 'linux'
data = {
'id': str(self.id),
'name': self.hostname,
'title': self.ip,
'pId': parent_node.key,
'isParent': False,
'open': False,
'iconSkin': icon_skin,
'meta': {
'type': 'asset',
'asset': {
'id': self.id,
'hostname': self.hostname,
'ip': self.ip,
'port': self.port,
'platform': self.platform,
'protocol': self.protocol,
}
}
}
tree_node = TreeNode(**data)
return tree_node
class Meta: class Meta:
unique_together = [('org_id', 'hostname')] unique_together = [('org_id', 'hostname')]
verbose_name = _("Asset") verbose_name = _("Asset")
......
...@@ -5,6 +5,7 @@ import uuid ...@@ -5,6 +5,7 @@ import uuid
from django.db import models, transaction from django.db import models, transaction
from django.db.models import Q from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext
from django.core.cache import cache from django.core.cache import cache
from orgs.mixins import OrgModelMixin from orgs.mixins import OrgModelMixin
...@@ -103,6 +104,15 @@ class Node(OrgModelMixin): ...@@ -103,6 +104,15 @@ class Node(OrgModelMixin):
key = self._full_value_cache_key.format(self.key) key = self._full_value_cache_key.format(self.key)
cache.delete_pattern(key+'*') cache.delete_pattern(key+'*')
@classmethod
def expire_nodes_full_value(cls, nodes=None):
if nodes:
for node in nodes:
node.expire_full_value()
return
key = cls._full_value_cache_key.format('*')
cache.delete_pattern(key+'*')
@property @property
def level(self): def level(self):
return len(self.key.split(':')) return len(self.key.split(':'))
...@@ -113,6 +123,17 @@ class Node(OrgModelMixin): ...@@ -113,6 +123,17 @@ class Node(OrgModelMixin):
self.save() self.save()
return "{}:{}".format(self.key, mark) return "{}:{}".format(self.key, mark)
def get_next_child_preset_name(self):
name = ugettext("New node")
values = [
child.value[child.value.rfind(' '):]
for child in self.get_children()
if child.value.startswith(name)
]
values = [int(value) for value in values if value.strip().isdigit()]
count = max(values) + 1 if values else 1
return '{} {}'.format(name, count)
def create_child(self, value): def create_child(self, value):
with transaction.atomic(): with transaction.atomic():
child_key = self.get_next_child_key() child_key = self.get_next_child_key()
...@@ -162,7 +183,7 @@ class Node(OrgModelMixin): ...@@ -162,7 +183,7 @@ class Node(OrgModelMixin):
pattern = r'^{0}$|^{0}:'.format(self.key) pattern = r'^{0}$|^{0}:'.format(self.key)
args = [] args = []
kwargs = {} kwargs = {}
if self.is_default_node(): if self.is_root():
args.append(Q(nodes__key__regex=pattern) | Q(nodes=None)) args.append(Q(nodes__key__regex=pattern) | Q(nodes=None))
else: else:
kwargs['nodes__key__regex'] = pattern kwargs['nodes__key__regex'] = pattern
...@@ -256,6 +277,26 @@ class Node(OrgModelMixin): ...@@ -256,6 +277,26 @@ class Node(OrgModelMixin):
defaults = {'value': 'Default'} defaults = {'value': 'Default'}
return cls.objects.get_or_create(defaults=defaults, key='1') return cls.objects.get_or_create(defaults=defaults, key='1')
def as_tree_node(self):
from common.tree import TreeNode
from ..serializers import NodeSerializer
name = '{} ({})'.format(self.value, self.assets_amount)
node_serializer = NodeSerializer(instance=self)
data = {
'id': self.key,
'name': name,
'title': name,
'pId': self.parent_key,
'isParent': True,
'open': self.is_root(),
'meta': {
'node': node_serializer.data,
'type': 'node'
}
}
tree_node = TreeNode(**data)
return tree_node
@classmethod @classmethod
def generate_fake(cls, count=100): def generate_fake(cls, count=100):
import random import random
......
...@@ -9,6 +9,7 @@ from .system_user import AssetSystemUserSerializer ...@@ -9,6 +9,7 @@ from .system_user import AssetSystemUserSerializer
__all__ = [ __all__ = [
'AssetSerializer', 'AssetGrantedSerializer', 'MyAssetGrantedSerializer', 'AssetSerializer', 'AssetGrantedSerializer', 'MyAssetGrantedSerializer',
'AssetAsNodeSerializer',
] ]
...@@ -22,6 +23,13 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -22,6 +23,13 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
fields = '__all__' fields = '__all__'
validators = [] validators = []
@classmethod
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.prefetch_related('labels', 'nodes')\
.select_related('admin_user')
return queryset
def get_field_names(self, declared_fields, info): def get_field_names(self, declared_fields, info):
fields = super().get_field_names(declared_fields, info) fields = super().get_field_names(declared_fields, info)
fields.extend([ fields.extend([
...@@ -30,6 +38,12 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer): ...@@ -30,6 +38,12 @@ class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
return fields return fields
class AssetAsNodeSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = ['id', 'hostname', 'ip', 'port', 'platform', 'protocol']
class AssetGrantedSerializer(serializers.ModelSerializer): class AssetGrantedSerializer(serializers.ModelSerializer):
""" """
被授权资产的数据结构 被授权资产的数据结构
......
...@@ -8,76 +8,33 @@ from .asset import AssetGrantedSerializer ...@@ -8,76 +8,33 @@ from .asset import AssetGrantedSerializer
__all__ = [ __all__ = [
'NodeSerializer', "NodeGrantedSerializer", "NodeAddChildrenSerializer", 'NodeSerializer', "NodeAddChildrenSerializer",
"NodeAssetsSerializer", "NodeAssetsSerializer",
] ]
class NodeGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
"""
授权资产组
"""
assets_granted = AssetGrantedSerializer(many=True, read_only=True)
assets_amount = serializers.SerializerMethodField()
parent = serializers.SerializerMethodField()
name = serializers.SerializerMethodField()
class Meta:
model = Node
fields = [
'id', 'key', 'name', 'value', 'parent',
'assets_granted', 'assets_amount', 'org_id',
]
@staticmethod
def get_assets_amount(obj):
return len(obj.assets_granted)
@staticmethod
def get_name(obj):
return obj.name
@staticmethod
def get_parent(obj):
return obj.parent.id
class NodeSerializer(serializers.ModelSerializer): class NodeSerializer(serializers.ModelSerializer):
assets_amount = serializers.IntegerField() assets_amount = serializers.IntegerField(read_only=True)
tree_id = serializers.SerializerMethodField()
tree_parent = serializers.SerializerMethodField()
class Meta: class Meta:
model = Node model = Node
fields = [ fields = [
'id', 'key', 'value', 'assets_amount', 'id', 'key', 'value', 'assets_amount', 'org_id',
'is_node', 'org_id', 'tree_id', 'tree_parent',
] ]
read_only_fields = [ read_only_fields = [
'id', 'key', 'assets_amount', 'is_node', 'id', 'key', 'assets_amount', 'org_id',
'org_id',
] ]
list_serializer_class = BulkListSerializer
def validate(self, data): def validate_value(self, data):
value = data.get('value')
instance = self.instance if self.instance else Node.root() instance = self.instance if self.instance else Node.root()
children = instance.parent.get_children().exclude(key=instance.key) children = instance.parent.get_children().exclude(key=instance.key)
values = [child.value for child in children] values = [child.value for child in children]
if value in values: if data in values:
raise serializers.ValidationError( raise serializers.ValidationError(
'The same level node name cannot be the same' 'The same level node name cannot be the same'
) )
return data return data
@staticmethod
def get_tree_id(obj):
return obj.key
@staticmethod
def get_tree_parent(obj):
return obj.parent_key
class NodeAssetsSerializer(serializers.ModelSerializer): class NodeAssetsSerializer(serializers.ModelSerializer):
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all()) assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
...@@ -89,3 +46,4 @@ class NodeAssetsSerializer(serializers.ModelSerializer): ...@@ -89,3 +46,4 @@ class NodeAssetsSerializer(serializers.ModelSerializer):
class NodeAddChildrenSerializer(serializers.Serializer): class NodeAddChildrenSerializer(serializers.Serializer):
nodes = serializers.ListField() nodes = serializers.ListField()
...@@ -136,6 +136,7 @@ ...@@ -136,6 +136,7 @@
<li class="divider"></li> <li class="divider"></li>
<li id="show_current_asset" class="btn-show-current-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-hand-o-up"></i> {% trans 'Display only current node assets' %}</a></li> <li id="show_current_asset" class="btn-show-current-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-hand-o-up"></i> {% trans 'Display only current node assets' %}</a></li>
<li id="show_all_asset" class="btn-show-all-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-th"></i> {% trans 'Displays all child node assets' %}</a></li> <li id="show_all_asset" class="btn-show-all-asset" style="display: none;" tabindex="-1"><a><i class="fa fa-th"></i> {% trans 'Displays all child node assets' %}</a></li>
<li id="fresh_tree" class="btn-refresh-tree" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh' %}</a></li>
</ul> </ul>
</div> </div>
...@@ -147,6 +148,8 @@ ...@@ -147,6 +148,8 @@
<script> <script>
var zTree, rMenu, asset_table, show = 0; var zTree, rMenu, asset_table, show = 0;
var update_node_action = ""; var update_node_action = "";
var current_node_id = null;
var current_node = null;
function initTable() { function initTable() {
var options = { var options = {
ele: $('#asset_list_table'), ele: $('#asset_list_table'),
...@@ -191,18 +194,20 @@ function addTreeNode() { ...@@ -191,18 +194,20 @@ function addTreeNode() {
if (!parentNode){ if (!parentNode){
return return
} }
var url = "{% url 'api-assets:node-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", parentNode.node_id ); var url = "{% url 'api-assets:node-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", parentNode.meta.node.id);
$.post(url, {}, function (data, status){ $.post(url, {}, function (data, status){
if (status === "success") { if (status === "success") {
var newNode = { var newNode = {
id: data["key"], id: data["key"],
name: data["value"], name: data["value"],
node_id: data["id"], pId: parentNode.id,
pId: parentNode.id meta: {
"node": data
}
}; };
newNode.checked = zTree.getSelectedNodes()[0].checked; newNode.checked = zTree.getSelectedNodes()[0].checked;
zTree.addNodes(parentNode, 0, newNode); zTree.addNodes(parentNode, 0, newNode);
var node = zTree.getNodeByParam('id', newNode.node_id, parentNode); var node = zTree.getNodeByParam('id', newNode.id, parentNode);
zTree.editName(node); zTree.editName(node);
} else { } else {
alert("{% trans 'Create node failed' %}") alert("{% trans 'Create node failed' %}")
...@@ -218,10 +223,10 @@ function removeTreeNode() { ...@@ -218,10 +223,10 @@ function removeTreeNode() {
} }
if (current_node.children && current_node.children.length > 0) { if (current_node.children && current_node.children.length > 0) {
toastr.error("{% trans 'Have child node, cancel' %}"); toastr.error("{% trans 'Have child node, cancel' %}");
} else if (current_node.assets_amount !== 0) { } else if (current_node.meta.node.assets_amount !== 0) {
toastr.error("{% trans 'Have assets, cancel' %}"); toastr.error("{% trans 'Have assets, cancel' %}");
} else { } else {
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node.node_id ); var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
$.ajax({ $.ajax({
url: url, url: url,
method: "DELETE", method: "DELETE",
...@@ -238,8 +243,8 @@ function editTreeNode() { ...@@ -238,8 +243,8 @@ function editTreeNode() {
if (!current_node){ if (!current_node){
return return
} }
if (current_node.value) { if (current_node) {
current_node.name = current_node.value; current_node.name = current_node.meta.node.value;
} }
zTree.editName(current_node); zTree.editName(current_node);
} }
...@@ -281,7 +286,7 @@ function onBodyMouseDown(event){ ...@@ -281,7 +286,7 @@ function onBodyMouseDown(event){
function onRename(event, treeId, treeNode, isCancel){ function onRename(event, treeId, treeNode, isCancel){
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", treeNode.node_id); var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
var data = {"value": treeNode.name}; var data = {"value": treeNode.name};
if (isCancel){ if (isCancel){
return return
...@@ -291,13 +296,20 @@ function onRename(event, treeId, treeNode, isCancel){ ...@@ -291,13 +296,20 @@ function onRename(event, treeId, treeNode, isCancel){
body: JSON.stringify(data), body: JSON.stringify(data),
method: "PATCH", method: "PATCH",
success_message: "{% trans 'Rename success' %}", success_message: "{% trans 'Rename success' %}",
fail_message: "{% trans 'Rename failed, do not change the root node name' %}" fail_message: "{% trans 'Rename failed, do not change the root node name' %}",
success: function () {
treeNode.name = treeNode.name + ' (' + treeNode.meta.node.assets_amount + ')'
zTree.updateNode(treeNode);
console.log("Success: " + treeNode.name)
}
}) })
} }
function onSelected(event, treeNode) { function onSelected(event, treeNode) {
current_node = treeNode;
current_node_id = treeNode.meta.node.id;
var url = asset_table.ajax.url(); var url = asset_table.ajax.url();
url = setUrlParam(url, "node_id", treeNode.node_id); url = setUrlParam(url, "node_id", current_node_id);
url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset')); url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset'));
setCookie('node_selected', treeNode.node_id); setCookie('node_selected', treeNode.node_id);
asset_table.ajax.url(url); asset_table.ajax.url(url);
...@@ -361,6 +373,11 @@ function initTree() { ...@@ -361,6 +373,11 @@ function initTree() {
if (zTree) { if (zTree) {
return return
} }
var url = '{% url 'api-assets:node-children-tree' %}?assets=0&all=';
var showCurrentAsset = getCookie('show_current_asset');
if (!showCurrentAsset) {
url += '1'
}
var setting = { var setting = {
view: { view: {
dblClickExpand: false, dblClickExpand: false,
...@@ -371,6 +388,12 @@ function initTree() { ...@@ -371,6 +388,12 @@ function initTree() {
enable: true enable: true
} }
}, },
async: {
enable: true,
url: url,
autoParam: ["id=key", "name=n", "level=lv"],
type: 'get'
},
edit: { edit: {
enable: true, enable: true,
showRemoveBtn: false, showRemoveBtn: false,
...@@ -393,27 +416,8 @@ function initTree() { ...@@ -393,27 +416,8 @@ function initTree() {
}; };
var zNodes = []; var zNodes = [];
console.log("Get assets") zTree = $.fn.zTree.init($("#assetTree"), setting, zNodes);
$.get("{% url 'api-assets:node-list' %}", function(data, status){ rMenu = $("#rMenu");
$.each(data, function (index, value) {
value["node_id"] = value["id"];
value["id"] = value["tree_id"];
if (value["tree_id"] !== value["tree_parent"]){
value["pId"] = value["tree_parent"];
} else {
value["isParent"] = true;
}
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')';
value['value'] = value['value'];
});
zNodes = data;
$.fn.zTree.init($("#assetTree"), setting, zNodes);
zTree = $.fn.zTree.getZTreeObj("assetTree");
var root = zTree.getNodes()[0];
zTree.expandNode(root);
rMenu = $("#rMenu");
selectQueryNode();
});
} }
function toggle() { function toggle() {
...@@ -450,20 +454,15 @@ $(document).ready(function(){ ...@@ -450,20 +454,15 @@ $(document).ready(function(){
.on('click', '.btn_export', function () { .on('click', '.btn_export', function () {
var $data_table = $('#asset_list_table').DataTable(); var $data_table = $('#asset_list_table').DataTable();
var rows = $data_table.rows('.selected').data(); var rows = $data_table.rows('.selected').data();
var nodes = zTree.getSelectedNodes();
var current_node;
if (nodes && nodes.length === 1) {
current_node = nodes[0];
}
var assets = []; var assets = [];
$.each(rows, function (index, obj) { $.each(rows, function (index, obj) {
assets.push(obj.id) assets.push(obj.id)
}); });
var _node_id = current_node ? current_node.node_id : null;
$.ajax({ $.ajax({
url: "{% url "assets:asset-export" %}", url: "{% url "assets:asset-export" %}",
method: 'POST', method: 'POST',
data: JSON.stringify({assets_id: assets, node_id: _node_id}), data: JSON.stringify({assets_id: assets, node_id: current_node_id}),
dataType: "json", dataType: "json",
success: function (data, textStatus) { success: function (data, textStatus) {
window.open(data.redirect) window.open(data.redirect)
...@@ -476,12 +475,8 @@ $(document).ready(function(){ ...@@ -476,12 +475,8 @@ $(document).ready(function(){
.on('click', '#btn_asset_import', function () { .on('click', '#btn_asset_import', function () {
var $form = $('#fm_asset_import'); var $form = $('#fm_asset_import');
var action = $form.attr("action"); var action = $form.attr("action");
var nodes = zTree.getSelectedNodes(); if (current_node_id){
var current_node; action = setUrlParam(action, 'node_id', current_node_id);
if (nodes && nodes.length ===1 ){
current_node = nodes[0];
action = setUrlParam(action, 'node_id', current_node.node_id);
{#action += "?node_id=" + current_node.node_id;#}
$form.attr("action", action) $form.attr("action", action)
} }
$form.find('.help-block').remove(); $form.find('.help-block').remove();
...@@ -503,25 +498,14 @@ $(document).ready(function(){ ...@@ -503,25 +498,14 @@ $(document).ready(function(){
}) })
.on('click', '.btn-create-asset', function () { .on('click', '.btn-create-asset', function () {
var url = "{% url 'assets:asset-create' %}"; var url = "{% url 'assets:asset-create' %}";
var nodes = zTree.getSelectedNodes(); if (current_node_id) {
var current_node; url += "?node_id=" + current_node_id;
if (nodes && nodes.length ===1 ){
current_node = nodes[0];
url += "?node_id=" + current_node.node_id;
} }
window.open(url, '_self'); window.open(url, '_self');
}) })
.on('click', '.btn-refresh-hardware', function () { .on('click', '.btn-refresh-hardware', function () {
var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}"; var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}";
var nodes = zTree.getSelectedNodes(); var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
var current_node;
if (nodes && nodes.length ===1 ){
current_node = nodes[0];
} else {
return null;
}
var the_url = url.replace("{{ DEFAULT_PK }}", current_node.node_id);
function success(data) { function success(data) {
rMenu.css({"visibility" : "hidden"}); rMenu.css({"visibility" : "hidden"});
var task_id = data.task; var task_id = data.task;
...@@ -538,15 +522,10 @@ $(document).ready(function(){ ...@@ -538,15 +522,10 @@ $(document).ready(function(){
}) })
.on('click', '.btn-test-connective', function () { .on('click', '.btn-test-connective', function () {
var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}"; var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}";
var nodes = zTree.getSelectedNodes(); if (!current_node_id) {
var current_node;
if (nodes && nodes.length ===1 ){
current_node = nodes[0];
} else {
return null; return null;
} }
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
var the_url = url.replace("{{ DEFAULT_PK }}", current_node.node_id);
function success(data) { function success(data) {
rMenu.css({"visibility" : "hidden"}); rMenu.css({"visibility" : "hidden"});
var task_id = data.task; var task_id = data.task;
...@@ -574,6 +553,10 @@ $(document).ready(function(){ ...@@ -574,6 +553,10 @@ $(document).ready(function(){
setCookie('show_current_asset', ''); setCookie('show_current_asset', '');
location.reload(); location.reload();
}) })
.on('click', '.btn-test-connective', function () {
hideRMenu();
})
.on('click', '.btn_asset_delete', function () { .on('click', '.btn_asset_delete', function () {
var $this = $(this); var $this = $(this);
var $data_table = $("#asset_list_table").DataTable(); var $data_table = $("#asset_list_table").DataTable();
...@@ -667,11 +650,8 @@ $(document).ready(function(){ ...@@ -667,11 +650,8 @@ $(document).ready(function(){
} }
function doRemove() { function doRemove() {
var current_node;
var nodes = zTree.getSelectedNodes(); var nodes = zTree.getSelectedNodes();
if (nodes && nodes.length === 1) { if (!current_node_id) {
current_node = nodes[0]
} else {
return return
} }
...@@ -684,7 +664,7 @@ $(document).ready(function(){ ...@@ -684,7 +664,7 @@ $(document).ready(function(){
}; };
APIUpdateAttr({ APIUpdateAttr({
'url': '/api/assets/v1/nodes/' + current_node.node_id + '/assets/remove/', 'url': '/api/assets/v1/nodes/' + current_node_id + '/assets/remove/',
'method': 'PUT', 'method': 'PUT',
'body': JSON.stringify(data), 'body': JSON.stringify(data),
'success': success 'success': success
...@@ -713,11 +693,7 @@ $(document).ready(function(){ ...@@ -713,11 +693,7 @@ $(document).ready(function(){
}) })
.on('click', '#btn_asset_modal_confirm', function () { .on('click', '#btn_asset_modal_confirm', function () {
var assets_selected = asset_table2.selected; var assets_selected = asset_table2.selected;
var current_node; if (!current_node_id) {
var nodes = zTree.getSelectedNodes();
if (nodes && nodes.length === 1) {
current_node = nodes[0]
} else {
return return
} }
...@@ -729,9 +705,9 @@ $(document).ready(function(){ ...@@ -729,9 +705,9 @@ $(document).ready(function(){
var url = ''; var url = '';
if (update_node_action === "move") { if (update_node_action === "move") {
url = "{% url 'api-assets:node-replace-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node.node_id); url = "{% url 'api-assets:node-replace-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
} else { } else {
url = "{% url 'api-assets:node-add-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node.node_id); url = "{% url 'api-assets:node-add-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
} }
APIUpdateAttr({ APIUpdateAttr({
......
...@@ -53,6 +53,8 @@ urlpatterns = [ ...@@ -53,6 +53,8 @@ urlpatterns = [
path('system-user/<uuid:pk>/cmd-filter-rules/', path('system-user/<uuid:pk>/cmd-filter-rules/',
api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'), api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'),
path('nodes/tree/', api.NodeListAsTreeApi.as_view(), name='node-tree'),
path('nodes/children/tree/', api.NodeChildrenAsTreeApi.as_view(), name='node-children-tree'),
path('nodes/<uuid:pk>/children/', path('nodes/<uuid:pk>/children/',
api.NodeChildrenApi.as_view(), name='node-children'), api.NodeChildrenApi.as_view(), name='node-children'),
path('nodes/children/', api.NodeChildrenApi.as_view(), name='node-children-2'), path('nodes/children/', api.NodeChildrenApi.as_view(), name='node-children-2'),
......
...@@ -216,7 +216,6 @@ class AssetExportView(LoginRequiredMixin, View): ...@@ -216,7 +216,6 @@ class AssetExportView(LoginRequiredMixin, View):
return HttpResponse('Json object not valid', status=400) return HttpResponse('Json object not valid', status=400)
if not assets_id: if not assets_id:
print(node_id)
node = get_object_or_none(Node, id=node_id) if node_id else Node.root() node = get_object_or_none(Node, id=node_id) if node_id else Node.root()
assets = node.get_all_assets() assets = node.get_all_assets()
for asset in assets: for asset in assets:
......
...@@ -356,6 +356,7 @@ FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755 ...@@ -356,6 +356,7 @@ FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
# OTP settings # OTP settings
OTP_ISSUER_NAME = CONFIG.OTP_ISSUER_NAME OTP_ISSUER_NAME = CONFIG.OTP_ISSUER_NAME
OTP_VALID_WINDOW = CONFIG.OTP_VALID_WINDOW
# Auth LDAP settings # Auth LDAP settings
AUTH_LDAP = False AUTH_LDAP = False
......
...@@ -8,7 +8,7 @@ msgid "" ...@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-12-17 10:14+0800\n" "POT-Creation-Date: 2018-12-17 17:51+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
...@@ -17,19 +17,11 @@ msgstr "" ...@@ -17,19 +17,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: assets/api/node.py:58 #: assets/api/node.py:261
msgid "You can't update the root node name"
msgstr "不能修改根节点名称"
#: assets/api/node.py:82
msgid "New node {}"
msgstr "新节点 {}"
#: assets/api/node.py:222
msgid "Update node asset hardware information: {}" msgid "Update node asset hardware information: {}"
msgstr "更新节点资产硬件信息: {}" msgstr "更新节点资产硬件信息: {}"
#: assets/api/node.py:236 #: assets/api/node.py:275
msgid "Test if the assets under the node are connectable: {}" msgid "Test if the assets under the node are connectable: {}"
msgstr "测试节点下资产是否可连接: {}" msgstr "测试节点下资产是否可连接: {}"
...@@ -70,12 +62,12 @@ msgid "Domain" ...@@ -70,12 +62,12 @@ msgid "Domain"
msgstr "网域" msgstr "网域"
#: assets/forms/asset.py:41 assets/forms/asset.py:66 assets/forms/asset.py:80 #: assets/forms/asset.py:41 assets/forms/asset.py:66 assets/forms/asset.py:80
#: assets/forms/asset.py:131 assets/models/node.py:28 #: assets/forms/asset.py:131 assets/models/node.py:31
#: assets/templates/assets/asset_create.html:30 #: assets/templates/assets/asset_create.html:30
#: assets/templates/assets/asset_update.html:35 perms/forms.py:37 #: assets/templates/assets/asset_update.html:35 perms/forms.py:37
#: perms/forms.py:44 perms/models.py:79 #: perms/forms.py:44 perms/models.py:79
#: perms/templates/perms/asset_permission_list.html:57 #: perms/templates/perms/asset_permission_list.html:57
#: perms/templates/perms/asset_permission_list.html:151 #: perms/templates/perms/asset_permission_list.html:117
#: xpack/plugins/cloud/models.py:122 #: xpack/plugins/cloud/models.py:122
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:63 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:63
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:66 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:66
...@@ -116,7 +108,7 @@ msgid "Port" ...@@ -116,7 +108,7 @@ msgid "Port"
msgstr "端口" msgstr "端口"
#: assets/forms/domain.py:15 assets/forms/label.py:13 #: assets/forms/domain.py:15 assets/forms/label.py:13
#: assets/models/asset.py:260 assets/templates/assets/admin_user_list.html:28 #: assets/models/asset.py:290 assets/templates/assets/admin_user_list.html:28
#: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_detail.html:60
#: assets/templates/assets/domain_list.html:26 #: assets/templates/assets/domain_list.html:26
#: assets/templates/assets/label_list.html:16 #: assets/templates/assets/label_list.html:16
...@@ -126,7 +118,7 @@ msgstr "端口" ...@@ -126,7 +118,7 @@ msgstr "端口"
#: perms/models.py:31 #: perms/models.py:31
#: perms/templates/perms/asset_permission_create_update.html:40 #: perms/templates/perms/asset_permission_create_update.html:40
#: perms/templates/perms/asset_permission_list.html:56 #: perms/templates/perms/asset_permission_list.html:56
#: perms/templates/perms/asset_permission_list.html:148 #: perms/templates/perms/asset_permission_list.html:114
#: terminal/backends/command/models.py:13 terminal/models.py:138 #: terminal/backends/command/models.py:13 terminal/models.py:138
#: terminal/templates/terminal/command_list.html:40 #: terminal/templates/terminal/command_list.html:40
#: terminal/templates/terminal/command_list.html:73 #: terminal/templates/terminal/command_list.html:73
...@@ -619,7 +611,7 @@ msgstr "默认资产组" ...@@ -619,7 +611,7 @@ msgstr "默认资产组"
#: perms/models.py:29 #: perms/models.py:29
#: perms/templates/perms/asset_permission_create_update.html:36 #: perms/templates/perms/asset_permission_create_update.html:36
#: perms/templates/perms/asset_permission_list.html:54 #: perms/templates/perms/asset_permission_list.html:54
#: perms/templates/perms/asset_permission_list.html:142 templates/index.html:87 #: perms/templates/perms/asset_permission_list.html:108 templates/index.html:87
#: terminal/backends/command/models.py:12 terminal/models.py:137 #: terminal/backends/command/models.py:12 terminal/models.py:137
#: terminal/templates/terminal/command_list.html:32 #: terminal/templates/terminal/command_list.html:32
#: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/command_list.html:72
...@@ -634,7 +626,7 @@ msgstr "默认资产组" ...@@ -634,7 +626,7 @@ msgstr "默认资产组"
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
#: assets/models/label.py:19 assets/models/node.py:20 #: assets/models/label.py:19 assets/models/node.py:21
#: assets/templates/assets/label_list.html:15 common/models.py:30 #: assets/templates/assets/label_list.html:15 common/models.py:30
msgid "Value" msgid "Value"
msgstr "值" msgstr "值"
...@@ -643,10 +635,14 @@ msgstr "值" ...@@ -643,10 +635,14 @@ msgstr "值"
msgid "Category" msgid "Category"
msgstr "分类" msgstr "分类"
#: assets/models/node.py:19 #: assets/models/node.py:20
msgid "Key" msgid "Key"
msgstr "" msgstr ""
#: assets/models/node.py:127
msgid "New node"
msgstr "新节点"
#: assets/models/user.py:109 #: assets/models/user.py:109
msgid "Automatic login" msgid "Automatic login"
msgstr "自动登录" msgstr "自动登录"
...@@ -702,7 +698,7 @@ msgstr "登录模式" ...@@ -702,7 +698,7 @@ msgstr "登录模式"
#: perms/models.py:33 perms/models.py:81 #: perms/models.py:33 perms/models.py:81
#: perms/templates/perms/asset_permission_detail.html:140 #: perms/templates/perms/asset_permission_detail.html:140
#: perms/templates/perms/asset_permission_list.html:58 #: perms/templates/perms/asset_permission_list.html:58
#: perms/templates/perms/asset_permission_list.html:154 templates/_nav.html:25 #: perms/templates/perms/asset_permission_list.html:120 templates/_nav.html:25
#: terminal/backends/command/models.py:14 terminal/models.py:139 #: terminal/backends/command/models.py:14 terminal/models.py:139
#: terminal/templates/terminal/command_list.html:48 #: terminal/templates/terminal/command_list.html:48
#: terminal/templates/terminal/command_list.html:74 #: terminal/templates/terminal/command_list.html:74
...@@ -734,7 +730,7 @@ msgid "Asset may not be support ansible, skipped: {}" ...@@ -734,7 +730,7 @@ msgid "Asset may not be support ansible, skipped: {}"
msgstr "资产或许不支持ansible, 跳过: {}" msgstr "资产或许不支持ansible, 跳过: {}"
#: assets/tasks.py:111 assets/tasks.py:210 assets/tasks.py:325 #: assets/tasks.py:111 assets/tasks.py:210 assets/tasks.py:325
#: assets/tasks.py:431 #: assets/tasks.py:432
msgid "No assets matched, stop task" msgid "No assets matched, stop task"
msgstr "没有匹配到资产,结束任务" msgstr "没有匹配到资产,结束任务"
...@@ -742,10 +738,6 @@ msgstr "没有匹配到资产,结束任务" ...@@ -742,10 +738,6 @@ msgstr "没有匹配到资产,结束任务"
msgid "Update asset hardware info: {}" msgid "Update asset hardware info: {}"
msgstr "更新资产硬件信息: {}" msgstr "更新资产硬件信息: {}"
#: assets/tasks.py:148
msgid "Update assets hardware info period"
msgstr "定期更新资产硬件信息"
#: assets/tasks.py:230 #: assets/tasks.py:230
msgid "Test admin user connectability period: {}" msgid "Test admin user connectability period: {}"
msgstr "定期测试管理账号可连接性: {}" msgstr "定期测试管理账号可连接性: {}"
...@@ -758,11 +750,11 @@ msgstr "测试管理行号可连接性: {}" ...@@ -758,11 +750,11 @@ msgstr "测试管理行号可连接性: {}"
msgid "Test assets connectability" msgid "Test assets connectability"
msgstr "测试资产可连接性" msgstr "测试资产可连接性"
#: assets/tasks.py:251 assets/tasks.py:316 assets/tasks.py:422 #: assets/tasks.py:251 assets/tasks.py:316 assets/tasks.py:423
msgid "Asset has been disabled, skip: {}" msgid "Asset has been disabled, skip: {}"
msgstr "资产被禁用,跳过:{}" msgstr "资产被禁用,跳过:{}"
#: assets/tasks.py:255 assets/tasks.py:320 assets/tasks.py:426 #: assets/tasks.py:255 assets/tasks.py:320 assets/tasks.py:427
msgid "Asset may not be support ansible, skip: {}" msgid "Asset may not be support ansible, skip: {}"
msgstr "资产或许不支持ansible, 跳过: {}" msgstr "资产或许不支持ansible, 跳过: {}"
...@@ -782,20 +774,16 @@ msgstr "测试系统用户可连接性: {}" ...@@ -782,20 +774,16 @@ msgstr "测试系统用户可连接性: {}"
msgid "Test system user connectability: {} => {}" msgid "Test system user connectability: {} => {}"
msgstr "测试系统用户可连接性: {} => {}" msgstr "测试系统用户可连接性: {} => {}"
#: assets/tasks.py:359 #: assets/tasks.py:414
msgid "Test system user connectability period: {}"
msgstr "定期测试系统用户可连接性: {}"
#: assets/tasks.py:413
msgid "" msgid ""
"Push system user task skip, auto push not enable or protocol is not ssh: {}" "Push system user task skip, auto push not enable or protocol is not ssh: {}"
msgstr "推送系统用户任务跳过,自动推送没有打开,或协议不是ssh: {}" msgstr "推送系统用户任务跳过,自动推送没有打开,或协议不是ssh: {}"
#: assets/tasks.py:444 assets/tasks.py:458 #: assets/tasks.py:445 assets/tasks.py:459
msgid "Push system users to assets: {}" msgid "Push system users to assets: {}"
msgstr "推送系统用户到入资产: {}" msgstr "推送系统用户到入资产: {}"
#: assets/tasks.py:450 #: assets/tasks.py:451
msgid "Push system users to asset: {} => {}" msgid "Push system users to asset: {} => {}"
msgstr "推送系统用户到入资产: {} => {}" msgstr "推送系统用户到入资产: {} => {}"
...@@ -1015,7 +1003,7 @@ msgstr "测试" ...@@ -1015,7 +1003,7 @@ msgstr "测试"
#: assets/templates/assets/admin_user_detail.html:24 #: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:88 #: assets/templates/assets/admin_user_list.html:88
#: assets/templates/assets/asset_detail.html:24 #: assets/templates/assets/asset_detail.html:24
#: assets/templates/assets/asset_list.html:171 #: assets/templates/assets/asset_list.html:174
#: assets/templates/assets/cmd_filter_detail.html:29 #: assets/templates/assets/cmd_filter_detail.html:29
#: assets/templates/assets/cmd_filter_list.html:57 #: assets/templates/assets/cmd_filter_list.html:57
#: assets/templates/assets/cmd_filter_rule_list.html:86 #: assets/templates/assets/cmd_filter_rule_list.html:86
...@@ -1027,7 +1015,7 @@ msgstr "测试" ...@@ -1027,7 +1015,7 @@ msgstr "测试"
#: assets/templates/assets/system_user_detail.html:26 #: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:92 audits/models.py:32 #: assets/templates/assets/system_user_list.html:92 audits/models.py:32
#: perms/templates/perms/asset_permission_detail.html:30 #: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:200 #: perms/templates/perms/asset_permission_list.html:166
#: terminal/templates/terminal/terminal_detail.html:16 #: terminal/templates/terminal/terminal_detail.html:16
#: terminal/templates/terminal/terminal_list.html:71 #: terminal/templates/terminal/terminal_list.html:71
#: users/templates/users/user_detail.html:25 #: users/templates/users/user_detail.html:25
...@@ -1047,7 +1035,7 @@ msgstr "更新" ...@@ -1047,7 +1035,7 @@ msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28 #: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:89 #: assets/templates/assets/admin_user_list.html:89
#: assets/templates/assets/asset_detail.html:28 #: assets/templates/assets/asset_detail.html:28
#: assets/templates/assets/asset_list.html:172 #: assets/templates/assets/asset_list.html:175
#: assets/templates/assets/cmd_filter_detail.html:33 #: assets/templates/assets/cmd_filter_detail.html:33
#: assets/templates/assets/cmd_filter_list.html:58 #: assets/templates/assets/cmd_filter_list.html:58
#: assets/templates/assets/cmd_filter_rule_list.html:87 #: assets/templates/assets/cmd_filter_rule_list.html:87
...@@ -1062,7 +1050,7 @@ msgstr "更新" ...@@ -1062,7 +1050,7 @@ msgstr "更新"
#: common/templates/common/terminal_setting.html:112 #: common/templates/common/terminal_setting.html:112
#: ops/templates/ops/task_list.html:72 #: ops/templates/ops/task_list.html:72
#: perms/templates/perms/asset_permission_detail.html:34 #: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:201 #: perms/templates/perms/asset_permission_list.html:167
#: terminal/templates/terminal/terminal_list.html:73 #: terminal/templates/terminal/terminal_list.html:73
#: users/templates/users/user_detail.html:30 #: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32 #: users/templates/users/user_group_detail.html:32
...@@ -1089,7 +1077,7 @@ msgstr "选择节点" ...@@ -1089,7 +1077,7 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:208 #: assets/templates/assets/asset_detail.html:208
#: assets/templates/assets/asset_list.html:633 #: assets/templates/assets/asset_list.html:623
#: assets/templates/assets/cmd_filter_detail.html:106 #: assets/templates/assets/cmd_filter_detail.html:106
#: assets/templates/assets/system_user_asset.html:112 #: assets/templates/assets/system_user_asset.html:112
#: assets/templates/assets/system_user_detail.html:182 #: assets/templates/assets/system_user_detail.html:182
...@@ -1197,6 +1185,7 @@ msgid "Refresh hardware" ...@@ -1197,6 +1185,7 @@ msgid "Refresh hardware"
msgstr "更新硬件信息" msgstr "更新硬件信息"
#: assets/templates/assets/asset_detail.html:171 #: assets/templates/assets/asset_detail.html:171
#: assets/templates/assets/asset_list.html:139
msgid "Refresh" msgid "Refresh"
msgstr "刷新" msgstr "刷新"
...@@ -1293,27 +1282,27 @@ msgstr "仅显示当前节点资产" ...@@ -1293,27 +1282,27 @@ msgstr "仅显示当前节点资产"
msgid "Displays all child node assets" msgid "Displays all child node assets"
msgstr "显示所有子节点资产" msgstr "显示所有子节点资产"
#: assets/templates/assets/asset_list.html:208 #: assets/templates/assets/asset_list.html:213
msgid "Create node failed" msgid "Create node failed"
msgstr "创建节点失败" msgstr "创建节点失败"
#: assets/templates/assets/asset_list.html:220 #: assets/templates/assets/asset_list.html:225
msgid "Have child node, cancel" msgid "Have child node, cancel"
msgstr "存在子节点,不能删除" msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:222 #: assets/templates/assets/asset_list.html:227
msgid "Have assets, cancel" msgid "Have assets, cancel"
msgstr "存在资产,不能删除" msgstr "存在资产,不能删除"
#: assets/templates/assets/asset_list.html:293 #: assets/templates/assets/asset_list.html:298
msgid "Rename success" msgid "Rename success"
msgstr "重命名成功" msgstr "重命名成功"
#: assets/templates/assets/asset_list.html:294 #: assets/templates/assets/asset_list.html:299
msgid "Rename failed, do not change the root node name" msgid "Rename failed, do not change the root node name"
msgstr "重命名失败,不能更改root节点的名称" msgstr "重命名失败,不能更改root节点的名称"
#: assets/templates/assets/asset_list.html:627 #: assets/templates/assets/asset_list.html:617
#: assets/templates/assets/system_user_list.html:137 #: assets/templates/assets/system_user_list.html:137
#: users/templates/users/user_detail.html:380 #: users/templates/users/user_detail.html:380
#: users/templates/users/user_detail.html:406 #: users/templates/users/user_detail.html:406
...@@ -1323,11 +1312,11 @@ msgstr "重命名失败,不能更改root节点的名称" ...@@ -1323,11 +1312,11 @@ msgstr "重命名失败,不能更改root节点的名称"
msgid "Are you sure?" msgid "Are you sure?"
msgstr "你确认吗?" msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:628 #: assets/templates/assets/asset_list.html:618
msgid "This will delete the selected assets !!!" msgid "This will delete the selected assets !!!"
msgstr "删除选择资产" msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:631 #: assets/templates/assets/asset_list.html:621
#: assets/templates/assets/system_user_list.html:141 #: assets/templates/assets/system_user_list.html:141
#: common/templates/common/terminal_setting.html:163 #: common/templates/common/terminal_setting.html:163
#: users/templates/users/user_detail.html:384 #: users/templates/users/user_detail.html:384
...@@ -1340,16 +1329,16 @@ msgstr "删除选择资产" ...@@ -1340,16 +1329,16 @@ msgstr "删除选择资产"
msgid "Cancel" msgid "Cancel"
msgstr "取消" msgstr "取消"
#: assets/templates/assets/asset_list.html:637 #: assets/templates/assets/asset_list.html:627
msgid "Asset Deleted." msgid "Asset Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/asset_list.html:638 #: assets/templates/assets/asset_list.html:628
#: assets/templates/assets/asset_list.html:643 #: assets/templates/assets/asset_list.html:633
msgid "Asset Delete" msgid "Asset Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/asset_list.html:642 #: assets/templates/assets/asset_list.html:632
msgid "Asset Deleting failed." msgid "Asset Deleting failed."
msgstr "删除失败" msgstr "删除失败"
...@@ -1586,7 +1575,7 @@ msgstr "批量更新资产" ...@@ -1586,7 +1575,7 @@ msgstr "批量更新资产"
msgid "Update asset" msgid "Update asset"
msgstr "更新资产" msgstr "更新资产"
#: assets/views/asset.py:293 #: assets/views/asset.py:292
msgid "already exists" msgid "already exists"
msgstr "已经存在" msgstr "已经存在"
...@@ -1966,69 +1955,69 @@ msgstr "全部" ...@@ -1966,69 +1955,69 @@ msgstr "全部"
msgid "Auto" msgid "Auto"
msgstr "自动" msgstr "自动"
#: common/forms.py:144 #: common/forms.py:146
msgid "Password auth" msgid "Password auth"
msgstr "密码认证" msgstr "密码认证"
#: common/forms.py:147 #: common/forms.py:149
msgid "Public key auth" msgid "Public key auth"
msgstr "密钥认证" msgstr "密钥认证"
#: common/forms.py:150 #: common/forms.py:152
msgid "Heartbeat interval" msgid "Heartbeat interval"
msgstr "心跳间隔" msgstr "心跳间隔"
#: common/forms.py:150 ops/models/adhoc.py:38 #: common/forms.py:152 ops/models/adhoc.py:38
msgid "Units: seconds" msgid "Units: seconds"
msgstr "单位: 秒" msgstr "单位: 秒"
#: common/forms.py:153 #: common/forms.py:155
msgid "List sort by" msgid "List sort by"
msgstr "资产列表排序" msgstr "资产列表排序"
#: common/forms.py:156 #: common/forms.py:158
msgid "List page size" msgid "List page size"
msgstr "资产列表页面大小" msgstr "资产列表页面大小"
#: common/forms.py:168 #: common/forms.py:170
msgid "MFA Secondary certification" msgid "MFA Secondary certification"
msgstr "MFA 二次认证" msgstr "MFA 二次认证"
#: common/forms.py:170 #: common/forms.py:172
msgid "" msgid ""
"After opening, the user login must use MFA secondary authentication (valid " "After opening, the user login must use MFA secondary authentication (valid "
"for all users, including administrators)" "for all users, including administrators)"
msgstr "开启后,用户登录必须使用MFA二次认证(对所有用户有效,包括管理员)" msgstr "开启后,用户登录必须使用MFA二次认证(对所有用户有效,包括管理员)"
#: common/forms.py:177 #: common/forms.py:179
msgid "Limit the number of login failures" msgid "Limit the number of login failures"
msgstr "限制登录失败次数" msgstr "限制登录失败次数"
#: common/forms.py:182 #: common/forms.py:184
msgid "No logon interval" msgid "No logon interval"
msgstr "禁止登录时间间隔" msgstr "禁止登录时间间隔"
#: common/forms.py:184 #: common/forms.py:186
msgid "" msgid ""
"Tip: (unit/minute) if the user has failed to log in for a limited number of " "Tip: (unit/minute) if the user has failed to log in for a limited number of "
"times, no login is allowed during this time interval." "times, no login is allowed during this time interval."
msgstr "" msgstr ""
"提示:(单位:分)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录" "提示:(单位:分)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录"
#: common/forms.py:191 #: common/forms.py:193
msgid "Connection max idle time" msgid "Connection max idle time"
msgstr "SSH最大空闲时间" msgstr "SSH最大空闲时间"
#: common/forms.py:193 #: common/forms.py:195
msgid "" msgid ""
"If idle time more than it, disconnect connection(only ssh now) Unit: minute" "If idle time more than it, disconnect connection(only ssh now) Unit: minute"
msgstr "提示:(单位:分)如果超过该配置没有操作,连接会被断开(仅ssh)" msgstr "提示:(单位:分)如果超过该配置没有操作,连接会被断开(仅ssh)"
#: common/forms.py:199 #: common/forms.py:201
msgid "Password expiration time" msgid "Password expiration time"
msgstr "密码过期时间" msgstr "密码过期时间"
#: common/forms.py:202 #: common/forms.py:204
msgid "" msgid ""
"Tip: (unit: day) If the user does not update the password during the time, " "Tip: (unit: day) If the user does not update the password during the time, "
"the user password will expire failure;The password expiration reminder mail " "the user password will expire failure;The password expiration reminder mail "
...@@ -2038,45 +2027,45 @@ msgstr "" ...@@ -2038,45 +2027,45 @@ msgstr ""
"提示:(单位:天)如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期" "提示:(单位:天)如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期"
"提醒邮件将在密码过期前5天内由系统(每天)自动发送给用户" "提醒邮件将在密码过期前5天内由系统(每天)自动发送给用户"
#: common/forms.py:211 #: common/forms.py:213
msgid "Password minimum length" msgid "Password minimum length"
msgstr "密码最小长度 " msgstr "密码最小长度 "
#: common/forms.py:217 #: common/forms.py:219
msgid "Must contain capital letters" msgid "Must contain capital letters"
msgstr "必须包含大写字母" msgstr "必须包含大写字母"
#: common/forms.py:219 #: common/forms.py:221
msgid "" msgid ""
"After opening, the user password changes and resets must contain uppercase " "After opening, the user password changes and resets must contain uppercase "
"letters" "letters"
msgstr "开启后,用户密码修改、重置必须包含大写字母" msgstr "开启后,用户密码修改、重置必须包含大写字母"
#: common/forms.py:225 #: common/forms.py:227
msgid "Must contain lowercase letters" msgid "Must contain lowercase letters"
msgstr "必须包含小写字母" msgstr "必须包含小写字母"
#: common/forms.py:226 #: common/forms.py:228
msgid "" msgid ""
"After opening, the user password changes and resets must contain lowercase " "After opening, the user password changes and resets must contain lowercase "
"letters" "letters"
msgstr "开启后,用户密码修改、重置必须包含小写字母" msgstr "开启后,用户密码修改、重置必须包含小写字母"
#: common/forms.py:232 #: common/forms.py:234
msgid "Must contain numeric characters" msgid "Must contain numeric characters"
msgstr "必须包含数字字符" msgstr "必须包含数字字符"
#: common/forms.py:233 #: common/forms.py:235
msgid "" msgid ""
"After opening, the user password changes and resets must contain numeric " "After opening, the user password changes and resets must contain numeric "
"characters" "characters"
msgstr "开启后,用户密码修改、重置必须包含数字字符" msgstr "开启后,用户密码修改、重置必须包含数字字符"
#: common/forms.py:239 #: common/forms.py:241
msgid "Must contain special characters" msgid "Must contain special characters"
msgstr "必须包含特殊字符" msgstr "必须包含特殊字符"
#: common/forms.py:240 #: common/forms.py:242
msgid "" msgid ""
"After opening, the user password changes and resets must contain special " "After opening, the user password changes and resets must contain special "
"characters" "characters"
...@@ -2370,7 +2359,7 @@ msgid "Version detail" ...@@ -2370,7 +2359,7 @@ msgid "Version detail"
msgstr "版本详情" msgstr "版本详情"
#: ops/templates/ops/adhoc_detail.html:22 #: ops/templates/ops/adhoc_detail.html:22
#: ops/templates/ops/adhoc_history.html:22 ops/views/adhoc.py:124 #: ops/templates/ops/adhoc_history.html:22 ops/views/adhoc.py:127
msgid "Version run history" msgid "Version run history"
msgstr "执行历史" msgstr "执行历史"
...@@ -2434,7 +2423,7 @@ msgstr "失败/成功/总" ...@@ -2434,7 +2423,7 @@ msgstr "失败/成功/总"
msgid "Version" msgid "Version"
msgstr "版本" msgstr "版本"
#: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:137 #: ops/templates/ops/adhoc_history_detail.html:19 ops/views/adhoc.py:140
msgid "Run history detail" msgid "Run history detail"
msgstr "执行历史详情" msgstr "执行历史详情"
...@@ -2480,12 +2469,12 @@ msgid "Finished" ...@@ -2480,12 +2469,12 @@ msgid "Finished"
msgstr "结束" msgstr "结束"
#: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:20 #: ops/templates/ops/task_adhoc.html:19 ops/templates/ops/task_detail.html:20
#: ops/templates/ops/task_history.html:19 ops/views/adhoc.py:72 #: ops/templates/ops/task_history.html:19 ops/views/adhoc.py:75
msgid "Task detail" msgid "Task detail"
msgstr "任务详情" msgstr "任务详情"
#: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:23 #: ops/templates/ops/task_adhoc.html:22 ops/templates/ops/task_detail.html:23
#: ops/templates/ops/task_history.html:22 ops/views/adhoc.py:85 #: ops/templates/ops/task_history.html:22 ops/views/adhoc.py:88
msgid "Task versions" msgid "Task versions"
msgstr "任务各版本" msgstr "任务各版本"
...@@ -2532,9 +2521,9 @@ msgstr "任务开始: " ...@@ -2532,9 +2521,9 @@ msgstr "任务开始: "
msgid "Update task content: {}" msgid "Update task content: {}"
msgstr "更新任务内容: {}" msgstr "更新任务内容: {}"
#: ops/views/adhoc.py:49 ops/views/adhoc.py:71 ops/views/adhoc.py:84 #: ops/views/adhoc.py:49 ops/views/adhoc.py:74 ops/views/adhoc.py:87
#: ops/views/adhoc.py:97 ops/views/adhoc.py:110 ops/views/adhoc.py:123 #: ops/views/adhoc.py:100 ops/views/adhoc.py:113 ops/views/adhoc.py:126
#: ops/views/adhoc.py:136 ops/views/command.py:43 ops/views/command.py:67 #: ops/views/adhoc.py:139 ops/views/command.py:43 ops/views/command.py:67
msgid "Ops" msgid "Ops"
msgstr "作业中心" msgstr "作业中心"
...@@ -2542,7 +2531,7 @@ msgstr "作业中心" ...@@ -2542,7 +2531,7 @@ msgstr "作业中心"
msgid "Task list" msgid "Task list"
msgstr "任务列表" msgstr "任务列表"
#: ops/views/adhoc.py:98 #: ops/views/adhoc.py:101
msgid "Task run history" msgid "Task run history"
msgstr "执行历史" msgstr "执行历史"
...@@ -2557,7 +2546,7 @@ msgstr "组织管理" ...@@ -2557,7 +2546,7 @@ msgstr "组织管理"
#: perms/forms.py:31 perms/models.py:30 perms/models.py:80 #: perms/forms.py:31 perms/models.py:30 perms/models.py:80
#: perms/templates/perms/asset_permission_list.html:55 #: perms/templates/perms/asset_permission_list.html:55
#: perms/templates/perms/asset_permission_list.html:145 templates/_nav.html:14 #: perms/templates/perms/asset_permission_list.html:111 templates/_nav.html:14
#: users/forms.py:284 users/models/group.py:26 users/models/user.py:59 #: users/forms.py:284 users/models/group.py:26 users/models/user.py:59
#: users/templates/users/_select_user_modal.html:16 #: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:211 #: users/templates/users/user_detail.html:211
...@@ -4486,50 +4475,6 @@ msgstr "AWS (中国)" ...@@ -4486,50 +4475,6 @@ msgstr "AWS (中国)"
msgid "AWS (International)" msgid "AWS (International)"
msgstr "AWS (国际)" msgstr "AWS (国际)"
#: xpack/plugins/cloud/providers/base.py:76
msgid "任务执行开始: {}\n"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:79
msgid "检测账户有效性: {}"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:82
msgid "账户无效!\n"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:86
msgid "账户有效!\n"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:90
msgid ""
"\n"
"任务执行结束!\n"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:91
msgid ""
"查看任务详细信息路径: XPack -> 云管中心 -> 任务列表 -> 任务详情(点击任务名"
"称) -> 查看同步历史列表/实例列表\n"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:126
msgid "同步实例列表: {}"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:135
msgid "同步地域列表: {}\n"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:138
msgid "地域: {}"
msgstr ""
#: xpack/plugins/cloud/providers/base.py:148
msgid "实例: {}, 地域: {}"
msgstr ""
#: xpack/plugins/cloud/providers/qcloud.py:14 #: xpack/plugins/cloud/providers/qcloud.py:14
msgid "Qcloud" msgid "Qcloud"
msgstr "腾讯云" msgstr "腾讯云"
...@@ -4661,6 +4606,15 @@ msgstr "创建组织" ...@@ -4661,6 +4606,15 @@ msgstr "创建组织"
msgid "Update org" msgid "Update org"
msgstr "更新组织" msgstr "更新组织"
#~ msgid "You can't update the root node name"
#~ msgstr "不能修改根节点名称"
#~ msgid "Update assets hardware info period"
#~ msgstr "定期更新资产硬件信息"
#~ msgid "Test system user connectability period: {}"
#~ msgstr "定期测试系统用户可连接性: {}"
#~ msgid "Date finished" #~ msgid "Date finished"
#~ msgstr "结束日期" #~ msgstr "结束日期"
......
...@@ -16,7 +16,7 @@ from orgs.utils import set_to_root_org ...@@ -16,7 +16,7 @@ from orgs.utils import set_to_root_org
from .utils import AssetPermissionUtil from .utils import AssetPermissionUtil
from .models import AssetPermission from .models import AssetPermission
from .hands import AssetGrantedSerializer, User, UserGroup, Asset, Node, \ from .hands import AssetGrantedSerializer, User, UserGroup, Asset, Node, \
NodeGrantedSerializer, SystemUser, NodeSerializer SystemUser, NodeSerializer
from . import serializers from . import serializers
from .mixins import AssetsFilterMixin from .mixins import AssetsFilterMixin
...@@ -150,7 +150,7 @@ class UserGrantedNodesWithAssetsApi(AssetsFilterMixin, ListAPIView): ...@@ -150,7 +150,7 @@ class UserGrantedNodesWithAssetsApi(AssetsFilterMixin, ListAPIView):
用户授权的节点并带着节点下资产的api 用户授权的节点并带着节点下资产的api
""" """
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = NodeGrantedSerializer serializer_class = serializers.NodeGrantedSerializer
def change_org_if_need(self): def change_org_if_need(self):
if self.request.user.is_superuser or \ if self.request.user.is_superuser or \
...@@ -360,7 +360,7 @@ class UserGroupGrantedNodesApi(ListAPIView): ...@@ -360,7 +360,7 @@ class UserGroupGrantedNodesApi(ListAPIView):
class UserGroupGrantedNodesWithAssetsApi(ListAPIView): class UserGroupGrantedNodesWithAssetsApi(ListAPIView):
permission_classes = (IsOrgAdmin,) permission_classes = (IsOrgAdmin,)
serializer_class = NodeGrantedSerializer serializer_class = serializers.NodeGrantedSerializer
def get_queryset(self): def get_queryset(self):
user_group_id = self.kwargs.get('pk', '') user_group_id = self.kwargs.get('pk', '')
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
from common.permissions import AdminUserRequiredMixin from common.permissions import AdminUserRequiredMixin
from users.models import User, UserGroup from users.models import User, UserGroup
from assets.models import Asset, SystemUser, Node from assets.models import Asset, SystemUser, Node
from assets.serializers import AssetGrantedSerializer, NodeGrantedSerializer, NodeSerializer from assets.serializers import AssetGrantedSerializer, NodeSerializer
...@@ -83,6 +83,35 @@ class AssetPermissionNodeSerializer(serializers.ModelSerializer): ...@@ -83,6 +83,35 @@ class AssetPermissionNodeSerializer(serializers.ModelSerializer):
return obj.parent_key return obj.parent_key
class NodeGrantedSerializer(serializers.ModelSerializer):
"""
授权资产组
"""
assets_granted = AssetGrantedSerializer(many=True, read_only=True)
assets_amount = serializers.SerializerMethodField()
parent = serializers.SerializerMethodField()
name = serializers.SerializerMethodField()
class Meta:
model = Node
fields = [
'id', 'key', 'name', 'value', 'parent',
'assets_granted', 'assets_amount', 'org_id',
]
@staticmethod
def get_assets_amount(obj):
return len(obj.assets_granted)
@staticmethod
def get_name(obj):
return obj.name
@staticmethod
def get_parent(obj):
return obj.parent.id
class GrantedNodeSerializer(serializers.ModelSerializer): class GrantedNodeSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Node model = Node
......
...@@ -78,58 +78,24 @@ var zTree, table, show = 0; ...@@ -78,58 +78,24 @@ var zTree, table, show = 0;
function onSelected(event, treeNode) { function onSelected(event, treeNode) {
setCookie('node_selected', treeNode.id); setCookie('node_selected', treeNode.id);
var url = table.ajax.url(); var url = table.ajax.url();
if (treeNode.is_node) { if (treeNode.meta.type === 'node') {
url = setUrlParam(url, 'asset', ""); url = setUrlParam(url, 'asset', "");
url = setUrlParam(url, 'node', treeNode.node_id) url = setUrlParam(url, 'node', treeNode.meta.node.id)
} else { } else {
url = setUrlParam(url, 'node', ""); url = setUrlParam(url, 'node', "");
url = setUrlParam(url, 'asset', treeNode.node_id) url = setUrlParam(url, 'asset', treeNode.meta.asset.id)
} }
setCookie('node_selected', treeNode.node_id); setCookie('node_selected', treeNode.node_id);
table.ajax.url(url); table.ajax.url(url);
table.ajax.reload(); table.ajax.reload();
} }
function selectQueryNode() {
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]);
node.open = true;
}
}
function filter(treeId, parentNode, childNodes) {
$.each(childNodes, function (index, value) {
value["node_id"] = value["id"];
value["id"] = value["tree_id"];
if (value["tree_id"] !== value["tree_parent"]) {
value["pId"] = value["tree_parent"];
} else {
value["isParent"] = true;
}
value['name'] = value['value'];
value["iconSkin"] = value["is_node"] ? null : 'file';
{#value["pId"] = value["parent"];#}
{#value["name"] = value["value"];#}
value["isParent"] = value["is_node"];
});
return childNodes;
}
function beforeAsync(treeId, treeNode) { function beforeAsync(treeId, treeNode) {
return treeNode.is_node if (treeNode) {
return treeNode.meta.type === 'node'
}
return true
} }
function makeLabel(data) { function makeLabel(data) {
...@@ -235,9 +201,8 @@ function initTree() { ...@@ -235,9 +201,8 @@ function initTree() {
}, },
async: { async: {
enable: true, enable: true,
url: "{% url 'api-assets:node-children-2' %}?assets=1&all=", url: "{% url 'api-assets:node-children-tree' %}?assets=1",
autoParam:["node_id=id", "name=n", "level=lv"], autoParam:["id=key", "name=n", "level=lv"],
dataFilter: filter,
type: 'get' type: 'get'
}, },
callback: { callback: {
...@@ -245,25 +210,7 @@ function initTree() { ...@@ -245,25 +210,7 @@ function initTree() {
beforeAsync: beforeAsync beforeAsync: beforeAsync
} }
}; };
zTree = $.fn.zTree.init($("#assetTree"), setting);
var zNodes = [];
$.get("{% url 'api-assets:node-children-2' %}?assets=1", function(data, status){
$.each(data, function (index, value) {
value["node_id"] = value["id"];
value["id"] = value["tree_id"];
if (value["tree_id"] !== value["tree_parent"]) {
value["pId"] = value["tree_parent"];
}
value["isParent"] = value["is_node"];
value['name'] = value['value'];
value["iconSkin"] = value["is_node"] ? null : 'file';
});
zNodes = data;
$.fn.zTree.init($("#assetTree"), setting, zNodes);
zTree = $.fn.zTree.getZTreeObj("assetTree");
var root = zTree.getNodes()[0];
zTree.expandNode(root);
});
} }
function toggle() { function toggle() {
...@@ -299,10 +246,10 @@ $(document).ready(function(){ ...@@ -299,10 +246,10 @@ $(document).ready(function(){
var _nodes = []; var _nodes = [];
var _assets = []; var _assets = [];
$.each(nodes, function (id, node) { $.each(nodes, function (id, node) {
if (node.is_node) { if (node.meta.type === 'node') {
_nodes.push(node.node_id) _nodes.push(node.meta.node.id)
} else { } else {
_assets.push(node.node_id) _assets.push(node.meta.asset.id)
} }
}); });
url += "?assets=" + _assets.join(",") + "&nodes=" + _nodes.join(","); url += "?assets=" + _assets.join(",") + "&nodes=" + _nodes.join(",");
......
...@@ -292,7 +292,8 @@ def check_otp_code(otp_secret_key, otp_code): ...@@ -292,7 +292,8 @@ def check_otp_code(otp_secret_key, otp_code):
if not otp_secret_key or not otp_code: if not otp_secret_key or not otp_code:
return False return False
totp = pyotp.TOTP(otp_secret_key) totp = pyotp.TOTP(otp_secret_key)
return totp.verify(otp_code) otp_valid_window = settings.OTP_VALID_WINDOW or 0
return totp.verify(otp=otp_code, valid_window=otp_valid_window)
def get_password_check_rules(): def get_password_check_rules():
......
...@@ -100,6 +100,9 @@ class Config: ...@@ -100,6 +100,9 @@ class Config:
} }
AUTH_LDAP_START_TLS = False AUTH_LDAP_START_TLS = False
#
# OTP_VALID_WINDOW = 0
def __init__(self): def __init__(self):
pass pass
...@@ -200,6 +203,10 @@ class DockerConfig(Config): ...@@ -200,6 +203,10 @@ class DockerConfig(Config):
AUTH_LDAP_START_TLS = False AUTH_LDAP_START_TLS = False
#
OTP_VALID_WINDOW = int(os.environ.get("OTP_VALID_WINDOW")) if os.environ.get("OTP_VALID_WINDOW") else 0
# Default using Config settings, you can write if/else for different env # Default using Config settings, you can write if/else for different env
config = DockerConfig() config = DockerConfig()
...@@ -90,6 +90,9 @@ class Config: ...@@ -90,6 +90,9 @@ class Config:
# AUTH_OPENID_CLIENT_ID = 'client-id' # AUTH_OPENID_CLIENT_ID = 'client-id'
# AUTH_OPENID_CLIENT_SECRET = 'client-secret' # AUTH_OPENID_CLIENT_SECRET = 'client-secret'
#
# OTP_VALID_WINDOW = 0
def __init__(self): def __init__(self):
pass pass
......
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