diff --git a/apps/assets/api/asset.py b/apps/assets/api/asset.py
index 50c037df9..b3855eba1 100644
--- a/apps/assets/api/asset.py
+++ b/apps/assets/api/asset.py
@@ -43,6 +43,7 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
queryset = super().get_queryset()
admin_user_id = self.request.query_params.get('admin_user_id')
node_id = self.request.query_params.get("node_id")
+ show_current_asset = self.request.query_params.get("show_current_asset")
if admin_user_id:
admin_user = get_object_or_404(AdminUser, id=admin_user_id)
@@ -51,8 +52,11 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
node = get_object_or_404(Node, id=node_id)
if not node.is_root():
queryset = queryset.filter(
- nodes__key__regex='{}(:[0-9]+)*$'.format(node.key),
+ nodes__key__regex='^{}(:[0-9]+)*$'.format(node.key),
).distinct()
+ if show_current_asset and node_id:
+ queryset = queryset.filter(nodes=node_id).distinct()
+
return queryset
diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py
index cc940757f..b0e974f5c 100644
--- a/apps/assets/api/node.py
+++ b/apps/assets/api/node.py
@@ -14,6 +14,7 @@
# limitations under the License.
from rest_framework import generics, mixins
+from rest_framework.serializers import ValidationError
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_bulk import BulkModelViewSet
@@ -41,7 +42,14 @@ __all__ = [
class NodeViewSet(BulkModelViewSet):
queryset = Node.objects.all()
permission_classes = (IsSuperUser,)
- serializer_class = serializers.NodeSerializer
+ # serializer_class = serializers.NodeSerializer
+
+ def get_serializer_class(self):
+ show_current_asset = self.request.query_params.get('show_current_asset')
+ if show_current_asset:
+ return serializers.NodeCurrentSerializer
+ else:
+ return serializers.NodeSerializer
def perform_create(self, serializer):
child_key = Node.root().get_next_child_key()
@@ -83,16 +91,29 @@ class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
serializer_class = serializers.NodeSerializer
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):
if not request.data.get("value"):
- request.data["value"] = _("New node {}").format(
- Node.root().get_next_child_key().split(":")[-1]
- )
+ request.data["value"] = _("New node {}").format(self.counter())
return super().post(request, *args, **kwargs)
def create(self, request, *args, **kwargs):
instance = self.get_object()
value = request.data.get("value")
+ values = [child.value for child in instance.get_children()]
+ if value in values:
+ raise ValidationError(
+ 'The same level node name cannot be the same'
+ )
node = instance.create_child(value=value)
return Response(
{"id": node.id, "key": node.key, "value": node.value},
@@ -163,8 +184,9 @@ class NodeAddChildrenApi(generics.UpdateAPIView):
for node in children:
if not node:
continue
- node.parent = instance
- node.save()
+ # node.parent = instance
+ # node.save()
+ node.set_parent(instance)
return Response("OK")
@@ -191,6 +213,9 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
instance = self.get_object()
if instance != Node.root():
instance.assets.remove(*tuple(assets))
+ else:
+ assets = [asset for asset in assets if asset.nodes.count() > 1]
+ instance.assets.remove(*tuple(assets))
class NodeReplaceAssetsApi(generics.UpdateAPIView):
diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py
index b4e46cc78..1be316567 100644
--- a/apps/assets/api/system_user.py
+++ b/apps/assets/api/system_user.py
@@ -58,6 +58,9 @@ class SystemUserPushApi(generics.RetrieveAPIView):
def retrieve(self, request, *args, **kwargs):
system_user = self.get_object()
+ nodes = system_user.nodes.all()
+ for node in nodes:
+ system_user.assets.add(*tuple(node.get_all_assets()))
task = push_system_user_to_assets_manual.delay(system_user)
return Response({"task": task.id})
diff --git a/apps/assets/models/base.py b/apps/assets/models/base.py
index eda00a79a..11afd92cf 100644
--- a/apps/assets/models/base.py
+++ b/apps/assets/models/base.py
@@ -104,10 +104,15 @@ class AssetUser(models.Model):
if update_fields:
self.save(update_fields=update_fields)
+ def clear_auth(self):
+ self._password = ''
+ self._private_key = ''
+ self.save()
+
def auto_gen_auth(self):
password = str(uuid.uuid4())
private_key, public_key = ssh_key_gen(
- username=self.username, password=password
+ username=self.username
)
self.set_auth(password=password,
private_key=private_key,
diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py
index 7939ad1e9..5ee97af9b 100644
--- a/apps/assets/models/node.py
+++ b/apps/assets/models/node.py
@@ -2,7 +2,7 @@
#
import uuid
-from django.db import models
+from django.db import models, transaction
from django.utils.translation import ugettext_lazy as _
@@ -12,7 +12,10 @@ __all__ = ['Node']
class Node(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
key = models.CharField(unique=True, max_length=64, verbose_name=_("Key")) # '1:1:1:1'
- value = models.CharField(max_length=128, unique=True, verbose_name=_("Value"))
+ # value = models.CharField(
+ # max_length=128, unique=True, verbose_name=_("Value")
+ # )
+ value = models.CharField(max_length=128, verbose_name=_("Value"))
child_mark = models.IntegerField(default=0)
date_create = models.DateTimeField(auto_now_add=True)
@@ -36,6 +39,16 @@ class Node(models.Model):
def level(self):
return len(self.key.split(':'))
+ def set_parent(self, instance):
+ children = self.get_all_children()
+ old_key = self.key
+ with transaction.atomic():
+ self.parent = instance
+ for child in children:
+ child.key = child.key.replace(old_key, self.key, 1)
+ child.save()
+ self.save()
+
def get_next_child_key(self):
mark = self.child_mark
self.child_mark += 1
@@ -48,7 +61,7 @@ class Node(models.Model):
return child
def get_children(self):
- return self.__class__.objects.filter(key__regex=r'{}:[0-9]+$'.format(self.key))
+ return self.__class__.objects.filter(key__regex=r'^{}:[0-9]+$'.format(self.key))
def get_all_children(self):
return self.__class__.objects.filter(key__startswith='{}:'.format(self.key))
@@ -75,6 +88,11 @@ class Node(models.Model):
assets = Asset.objects.filter(nodes__in=nodes).distinct()
return assets
+ def get_current_assets(self):
+ from .asset import Asset
+ assets = Asset.objects.filter(nodes=self).distinct()
+ return assets
+
def has_assets(self):
return self.get_all_assets()
diff --git a/apps/assets/serializers/node.py b/apps/assets/serializers/node.py
index 5b58ff241..b191b0a4f 100644
--- a/apps/assets/serializers/node.py
+++ b/apps/assets/serializers/node.py
@@ -9,7 +9,7 @@ from .asset import AssetGrantedSerializer
__all__ = [
'NodeSerializer', "NodeGrantedSerializer", "NodeAddChildrenSerializer",
- "NodeAssetsSerializer",
+ "NodeAssetsSerializer", "NodeCurrentSerializer",
]
@@ -51,6 +51,17 @@ class NodeSerializer(serializers.ModelSerializer):
fields = ['id', 'key', 'value', 'parent', 'assets_amount', 'is_node']
list_serializer_class = BulkListSerializer
+ def validate(self, data):
+ value = data.get('value')
+ instance = self.instance if self.instance else Node.root()
+ children = instance.parent.get_children().exclude(key=instance.key)
+ values = [child.value for child in children]
+ if value in values:
+ raise serializers.ValidationError(
+ 'The same level node name cannot be the same'
+ )
+ return data
+
@staticmethod
def get_parent(obj):
return obj.parent.id
@@ -66,6 +77,12 @@ class NodeSerializer(serializers.ModelSerializer):
return fields
+class NodeCurrentSerializer(NodeSerializer):
+ @staticmethod
+ def get_assets_amount(obj):
+ return obj.get_current_assets().count()
+
+
class NodeAssetsSerializer(serializers.ModelSerializer):
assets = serializers.PrimaryKeyRelatedField(many=True, queryset=Asset.objects.all())
diff --git a/apps/assets/templates/assets/_asset_list_modal.html b/apps/assets/templates/assets/_asset_list_modal.html
index c5cd48857..db7d165e0 100644
--- a/apps/assets/templates/assets/_asset_list_modal.html
+++ b/apps/assets/templates/assets/_asset_list_modal.html
@@ -98,7 +98,10 @@ function initTree2() {
$.get("{% url 'api-assets:node-list' %}", function(data, status){
$.each(data, function (index, value) {
value["pId"] = value["parent"];
- value["open"] = true;
+ {#value["open"] = true;#}
+ if (value["key"] === "0") {
+ value["open"] = true;
+ }
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')';
value['value'] = value['value'];
});
diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html
index 528e271e6..314967d22 100644
--- a/apps/assets/templates/assets/_system_user.html
+++ b/apps/assets/templates/assets/_system_user.html
@@ -55,7 +55,7 @@
{% bootstrap_field form.private_key_file layout="horizontal" %}
{% endblock %}
{% block custom_foot_js %}
-
+$(document).ready(function () {
+ $('.select2').select2();
+ authFieldsDisplay();
+ protocolChange();
+})
+.on('change', protocol_id, function(){
+ protocolChange();
+})
+.on('change', auto_generate_key, function(){
+ authFieldsDisplay();
+});
+
+
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/admin_user_assets.html b/apps/assets/templates/assets/admin_user_assets.html
index 80ff0cd5f..31314392f 100644
--- a/apps/assets/templates/assets/admin_user_assets.html
+++ b/apps/assets/templates/assets/admin_user_assets.html
@@ -124,7 +124,7 @@ $(document).ready(function () {
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
- window.open(url, '', 'width=800,height=600')
+ window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html
index 0b1b2865a..b07a7c348 100644
--- a/apps/assets/templates/assets/asset_detail.html
+++ b/apps/assets/templates/assets/asset_detail.html
@@ -190,7 +190,7 @@
|
@@ -204,7 +204,7 @@
{% for node in asset.nodes.all %}
- {{ node.name }} |
+ {{ node }} |
|
diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html
index 04ba11e57..0100e1e7f 100644
--- a/apps/assets/templates/assets/asset_list.html
+++ b/apps/assets/templates/assets/asset_list.html
@@ -47,7 +47,6 @@
@@ -87,7 +86,7 @@
{% trans 'IP' %} |
{% trans 'Hardware' %} |
{% trans 'Active' %} |
- {% trans 'Reachable' %} |
+{# {% trans 'Reachable' %} | #}
{% trans 'Action' %} |
@@ -127,6 +126,9 @@
+
+ {% trans 'Display only current node assets' %}
+ {% trans 'Displays all child node assets' %}
@@ -157,26 +159,35 @@ function initTable() {
$(td).html('')
}
}},
- {targets: 5, createdCell: function (td, cellData) {
- if (cellData === 'Unknown'){
- $(td).html('')
- } else if (!cellData) {
- $(td).html('')
- } else {
- $(td).html('')
- }
- }},
- {targets: 6, createdCell: function (td, cellData, rowData) {
+
+ {#{targets: 5, createdCell: function (td, cellData) {#}
+ {# if (cellData === 'Unknown'){#}
+ {# $(td).html('')#}
+ {# } else if (!cellData) {#}
+ {# $(td).html('')#}
+ {# } else {#}
+ {# $(td).html('')#}
+ {# }#}
+ {# }},#}
+
+ {targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '{% trans "Update" %}'.replace("{{ DEFAULT_PK }}", cellData);
var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
}}
],
ajax_url: '{% url "api-assets:asset-list" %}',
+
+ {#columns: [#}
+ {# {data: "id"}, {data: "hostname" }, {data: "ip" },#}
+ {# {data: "cpu_cores"}, {data: "is_active", orderable: false },#}
+ {# {data: "is_connective", orderable: false}, {data: "id", orderable: false }#}
+ {#],#}
+
columns: [
{data: "id"}, {data: "hostname" }, {data: "ip" },
{data: "cpu_cores"}, {data: "is_active", orderable: false },
- {data: "is_connective", orderable: false}, {data: "id", orderable: false }
+ {data: "id", orderable: false }
],
op_html: $('#actions').html()
};
@@ -200,6 +211,8 @@ function addTreeNode() {
};
newNode.checked = zTree.getSelectedNodes()[0].checked;
zTree.addNodes(parentNode, 0, newNode);
+ var node = zTree.getNodeByParam('id', newNode.id, parentNode)
+ zTree.editName(node);
} else {
alert("{% trans 'Create node failed' %}")
}
@@ -230,9 +243,9 @@ function removeTreeNode() {
function editTreeNode() {
hideRMenu();
- var current_node = zTree.getSelectedNodes()[0];
- if (!current_node){
- return
+ var current_node = zTree.getSelectedNodes()[0];
+ if (!current_node){
+ return
}
if (current_node.value) {
current_node.name = current_node.value;
@@ -290,6 +303,7 @@ function onRename(event, treeId, treeNode, isCancel){
function onSelected(event, treeNode) {
var url = asset_table.ajax.url();
url = setUrlParam(url, "node_id", treeNode.id);
+ url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset'));
setCookie('node_selected', treeNode.id);
asset_table.ajax.url(url);
asset_table.ajax.reload();
@@ -382,12 +396,13 @@ function initTree() {
};
var zNodes = [];
- $.get("{% url 'api-assets:node-list' %}", function(data, status){
+ var query_params = {'show_current_asset': getCookie('show_current_asset')};
+ $.get("{% url 'api-assets:node-list' %}", query_params, function(data, status){
$.each(data, function (index, value) {
value["pId"] = value["parent"];
- {#if (value["key"] === "0") {#}
- value["open"] = true;
- {# }#}
+ if (value["key"] === "0") {
+ value["open"] = true;
+ }
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')';
value['value'] = value['value'];
});
@@ -417,6 +432,13 @@ function toggle() {
$(document).ready(function(){
initTable();
initTree();
+
+ if(getCookie('show_current_asset') === 'yes'){
+ $('#show_all_asset').css('display', 'inline-block');
+ }
+ else{
+ $('#show_current_asset').css('display', 'inline-block');
+ }
})
.on('click', '.labels li', function () {
var val = $(this).text();
@@ -535,6 +557,20 @@ $(document).ready(function(){
flash_message: false
});
})
+.on('click', '.btn-show-current-asset', function(){
+ hideRMenu();
+ $(this).css('display', 'none');
+ $('#show_all_asset').css('display', 'inline-block');
+ setCookie('show_current_asset', 'yes');
+ location.reload();
+})
+.on('click', '.btn-show-all-asset', function(){
+ hideRMenu();
+ $(this).css('display', 'none');
+ $('#show_current_asset').css('display', 'inline-block');
+ setCookie('show_current_asset', '');
+ location.reload();
+})
.on('click', '.btn_asset_delete', function () {
var $this = $(this);
var $data_table = $("#asset_list_table").DataTable();
diff --git a/apps/assets/templates/assets/domain_gateway_list.html b/apps/assets/templates/assets/domain_gateway_list.html
index 581f6c08a..c2d5528ee 100644
--- a/apps/assets/templates/assets/domain_gateway_list.html
+++ b/apps/assets/templates/assets/domain_gateway_list.html
@@ -85,6 +85,9 @@ function initTable() {
var update_btn = '{% trans "Update" %}'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData);
var test_btn = '{% trans "Test connection" %}'.replace('{{ DEFAULT_PK }}', cellData);
+ if(rowData.protocol === 'rdp'){
+ test_btn = '{% trans "Test connection" %}'.replace('{{ DEFAULT_PK }}', cellData);
+ }
$(td).html(update_btn + test_btn + del_btn)
}}
],
@@ -120,7 +123,6 @@ $(document).ready(function(){
success_message: "可连接",
fail_message: "连接失败"
})
-
-})
+});
{% endblock %}
diff --git a/apps/assets/templates/assets/gateway_create_update.html b/apps/assets/templates/assets/gateway_create_update.html
index 7d6800c41..e0b10ba73 100644
--- a/apps/assets/templates/assets/gateway_create_update.html
+++ b/apps/assets/templates/assets/gateway_create_update.html
@@ -66,3 +66,28 @@
{% endblock %}
+
+{% block custom_foot_js %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html
index a02bf1e44..cc686a62b 100644
--- a/apps/assets/templates/assets/system_user_detail.html
+++ b/apps/assets/templates/assets/system_user_detail.html
@@ -64,14 +64,14 @@
{% trans 'Protocol' %}: |
- {{ system_user.protocol }} |
+ {{ system_user.protocol }} |
-
+
{% trans 'Sudo' %}: |
{{ system_user.sudo }} |
{% if system_user.shell %}
-
+
{% trans 'Shell' %}: |
{{ system_user.shell }} |
@@ -107,7 +107,7 @@
-
+
{% trans 'Quick update' %}
@@ -236,6 +236,9 @@ function updateSystemUserNode(nodes) {
}
jumpserver.nodes_selected = {};
$(document).ready(function () {
+ if($('#id_protocol_type').text() === 'rdp'){
+ $('.only-ssh').addClass('hidden')
+ }
$('.select2').select2()
.on('select2:select', function(evt) {
var data = evt.params.data;
@@ -296,7 +299,7 @@ $(document).ready(function () {
var success = function (data) {
var task_id = data.task;
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
- window.open(url, '', 'width=800,height=600')
+ window.open(url, '', 'width=800,height=600,left=400,top=400')
};
APIUpdateAttr({
url: the_url,
diff --git a/apps/assets/templates/assets/system_user_update.html b/apps/assets/templates/assets/system_user_update.html
index 46ef8d6a3..7e1590db5 100644
--- a/apps/assets/templates/assets/system_user_update.html
+++ b/apps/assets/templates/assets/system_user_update.html
@@ -15,10 +15,3 @@
{% endblock %}
-{% block custom_foot_js %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/apps/common/api.py b/apps/common/api.py
index 4b74b6b0d..209d09747 100644
--- a/apps/common/api.py
+++ b/apps/common/api.py
@@ -96,14 +96,7 @@ class LDAPTestingAPI(APIView):
class DjangoSettingsAPI(APIView):
def get(self, request):
- if not settings.DEBUG:
- return Response('Only debug mode support')
-
- configs = {}
- for i in dir(settings):
- if i.isupper():
- configs[i] = str(getattr(settings, i))
- return Response(configs)
+ return Response('Danger, Close now')
diff --git a/apps/i18n/zh/LC_MESSAGES/django.mo b/apps/i18n/zh/LC_MESSAGES/django.mo
index 038e65f43..36220e321 100644
Binary files a/apps/i18n/zh/LC_MESSAGES/django.mo and b/apps/i18n/zh/LC_MESSAGES/django.mo differ
diff --git a/apps/i18n/zh/LC_MESSAGES/django.po b/apps/i18n/zh/LC_MESSAGES/django.po
index 2dc77a3fd..8f95f9291 100644
--- a/apps/i18n/zh/LC_MESSAGES/django.po
+++ b/apps/i18n/zh/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-04-27 11:39+0800\n"
+"POT-Creation-Date: 2018-05-08 17:24+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler
\n"
"Language-Team: Jumpserver team\n"
@@ -17,15 +17,15 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: assets/api/node.py:88
+#: assets/api/node.py:96
msgid "New node {}"
msgstr "新节点 {}"
-#: assets/api/node.py:217
+#: assets/api/node.py:225
msgid "更新节点资产硬件信息: {}"
msgstr ""
-#: assets/api/node.py:230
+#: assets/api/node.py:238
msgid "测试节点下资产是否可连接: {}"
msgstr ""
@@ -46,7 +46,7 @@ msgstr "管理用户"
#: assets/forms/asset.py:30 assets/forms/asset.py:69 assets/forms/asset.py:125
#: assets/templates/assets/asset_create.html:35
#: assets/templates/assets/asset_create.html:37
-#: assets/templates/assets/asset_list.html:75
+#: assets/templates/assets/asset_list.html:74
#: assets/templates/assets/asset_update.html:40
#: assets/templates/assets/asset_update.html:42
#: assets/templates/assets/user_asset_list.html:34
@@ -206,7 +206,7 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
#: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/asset_detail.html:61
-#: assets/templates/assets/asset_list.html:87
+#: assets/templates/assets/asset_list.html:86
#: assets/templates/assets/domain_gateway_list.html:57
#: assets/templates/assets/system_user_asset.html:50
#: assets/templates/assets/user_asset_list.html:46 common/forms.py:144
@@ -220,7 +220,7 @@ msgstr "IP"
#: assets/models/asset.py:62 assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/asset_detail.html:57
-#: assets/templates/assets/asset_list.html:86
+#: assets/templates/assets/asset_list.html:85
#: assets/templates/assets/system_user_asset.html:49
#: assets/templates/assets/user_asset_list.html:45 common/forms.py:143
#: perms/templates/perms/asset_permission_asset.html:54
@@ -650,7 +650,7 @@ msgstr "重置"
#: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:67
-#: assets/templates/assets/asset_list.html:108
+#: assets/templates/assets/asset_list.html:107
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/gateway_create_update.html:59
@@ -699,7 +699,6 @@ msgstr "资产列表"
#: assets/templates/assets/admin_user_assets.html:54
#: assets/templates/assets/admin_user_list.html:26
-#: assets/templates/assets/asset_list.html:90
#: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/system_user_list.html:30
#: users/templates/users/user_group_granted_asset.html:47
@@ -728,7 +727,7 @@ msgstr "测试"
#: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/asset_detail.html:24
-#: assets/templates/assets/asset_list.html:170
+#: assets/templates/assets/asset_list.html:174
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:85
@@ -752,7 +751,7 @@ msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:86
#: assets/templates/assets/asset_detail.html:28
-#: assets/templates/assets/asset_list.html:171
+#: assets/templates/assets/asset_list.html:175
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:86
@@ -783,7 +782,7 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200
-#: assets/templates/assets/asset_list.html:600
+#: assets/templates/assets/asset_list.html:634
#: assets/templates/assets/system_user_detail.html:183
#: assets/templates/assets/system_user_list.html:138 templates/_modal.html:22
#: terminal/templates/terminal/session_detail.html:108
@@ -815,7 +814,7 @@ msgid "Ratio"
msgstr "比例"
#: assets/templates/assets/admin_user_list.html:30
-#: assets/templates/assets/asset_list.html:91
+#: assets/templates/assets/asset_list.html:90
#: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_list.html:18
#: assets/templates/assets/label_list.html:17
@@ -856,7 +855,7 @@ msgid "Quick modify"
msgstr "快速修改"
#: assets/templates/assets/asset_detail.html:143
-#: assets/templates/assets/asset_list.html:89
+#: assets/templates/assets/asset_list.html:88
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:35
#: perms/models.py:79
#: perms/templates/perms/asset_permission_create_update.html:47
@@ -886,89 +885,97 @@ msgstr "刷新"
msgid "Update successfully!"
msgstr "更新成功"
-#: assets/templates/assets/asset_list.html:63 assets/views/asset.py:97
+#: assets/templates/assets/asset_list.html:62 assets/views/asset.py:97
msgid "Create asset"
msgstr "创建资产"
-#: assets/templates/assets/asset_list.html:67
+#: assets/templates/assets/asset_list.html:66
#: users/templates/users/user_list.html:7
msgid "Import"
msgstr "导入"
-#: assets/templates/assets/asset_list.html:70
+#: assets/templates/assets/asset_list.html:69
#: users/templates/users/user_list.html:10
msgid "Export"
msgstr "导出"
-#: assets/templates/assets/asset_list.html:88
+#: assets/templates/assets/asset_list.html:87
msgid "Hardware"
msgstr "硬件"
-#: assets/templates/assets/asset_list.html:100
+#: assets/templates/assets/asset_list.html:99
#: users/templates/users/user_list.html:37
msgid "Delete selected"
msgstr "批量删除"
-#: assets/templates/assets/asset_list.html:101
+#: assets/templates/assets/asset_list.html:100
#: users/templates/users/user_list.html:38
msgid "Update selected"
msgstr "批量更新"
-#: assets/templates/assets/asset_list.html:102
+#: assets/templates/assets/asset_list.html:101
msgid "Remove from this node"
msgstr "从节点移除"
-#: assets/templates/assets/asset_list.html:103
+#: assets/templates/assets/asset_list.html:102
#: users/templates/users/user_list.html:39
msgid "Deactive selected"
msgstr "禁用所选"
-#: assets/templates/assets/asset_list.html:104
+#: assets/templates/assets/asset_list.html:103
#: users/templates/users/user_list.html:40
msgid "Active selected"
msgstr "激活所选"
-#: assets/templates/assets/asset_list.html:121
+#: assets/templates/assets/asset_list.html:120
msgid "Add node"
msgstr "新建节点"
-#: assets/templates/assets/asset_list.html:122
+#: assets/templates/assets/asset_list.html:121
msgid "Rename node"
msgstr "重命名节点"
-#: assets/templates/assets/asset_list.html:123
+#: assets/templates/assets/asset_list.html:122
msgid "Delete node"
msgstr "删除节点"
-#: assets/templates/assets/asset_list.html:125
+#: assets/templates/assets/asset_list.html:124
msgid "Add assets to node"
msgstr "添加资产到节点"
-#: assets/templates/assets/asset_list.html:126
+#: assets/templates/assets/asset_list.html:125
msgid "Move assets to node"
msgstr "移动资产到节点"
-#: assets/templates/assets/asset_list.html:128
+#: assets/templates/assets/asset_list.html:127
msgid "Refresh node hardware info"
msgstr "更新节点资产硬件信息"
-#: assets/templates/assets/asset_list.html:129
+#: assets/templates/assets/asset_list.html:128
msgid "Test node connective"
msgstr "测试节点资产可连接性"
-#: assets/templates/assets/asset_list.html:204
+#: assets/templates/assets/asset_list.html:130
+msgid "Display only current node assets"
+msgstr "仅显示当前节点资产"
+
+#: assets/templates/assets/asset_list.html:131
+msgid "Displays all child node assets"
+msgstr "显示所有子节点资产"
+
+#: assets/templates/assets/asset_list.html:215
msgid "Create node failed"
msgstr "创建节点失败"
-#: assets/templates/assets/asset_list.html:216
+#: assets/templates/assets/asset_list.html:227
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
-#: assets/templates/assets/asset_list.html:218
+#: assets/templates/assets/asset_list.html:229
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
-#: assets/templates/assets/asset_list.html:595
+#: assets/templates/assets/asset_list.html:629
#: assets/templates/assets/system_user_list.html:133
#: users/templates/users/user_detail.html:357
#: users/templates/users/user_detail.html:382
@@ -977,20 +984,20 @@ msgstr "存在资产,不能删除"
msgid "Are you sure?"
msgstr "你确认吗?"
-#: assets/templates/assets/asset_list.html:596
+#: assets/templates/assets/asset_list.html:630
msgid "This will delete the selected assets !!!"
msgstr "删除选择资产"
-#: assets/templates/assets/asset_list.html:604
+#: assets/templates/assets/asset_list.html:638
msgid "Asset Deleted."
msgstr "已被删除"
-#: assets/templates/assets/asset_list.html:605
-#: assets/templates/assets/asset_list.html:610
+#: assets/templates/assets/asset_list.html:639
+#: assets/templates/assets/asset_list.html:644
msgid "Asset Delete"
msgstr "删除"
-#: assets/templates/assets/asset_list.html:609
+#: assets/templates/assets/asset_list.html:643
msgid "Asset Deleting failed."
msgstr "删除失败"
diff --git a/apps/ops/api.py b/apps/ops/api.py
index 0134fbd4a..35c9b8dc5 100644
--- a/apps/ops/api.py
+++ b/apps/ops/api.py
@@ -72,7 +72,7 @@ class CeleryTaskLogApi(generics.RetrieveAPIView):
def get(self, request, *args, **kwargs):
mark = request.query_params.get("mark") or str(uuid.uuid4())
- task = super().get_object()
+ task = self.get_object()
log_path = task.full_log_path
if not log_path or not os.path.isfile(log_path):
diff --git a/apps/ops/templates/ops/adhoc_history_detail.html b/apps/ops/templates/ops/adhoc_history_detail.html
index 16adbc4e3..b8a48d4e5 100644
--- a/apps/ops/templates/ops/adhoc_history_detail.html
+++ b/apps/ops/templates/ops/adhoc_history_detail.html
@@ -19,7 +19,7 @@
{% trans 'Run history detail' %}
- {% trans 'Output' %}
+ {% trans 'Output' %}
diff --git a/apps/ops/templates/ops/celery_task_log.html b/apps/ops/templates/ops/celery_task_log.html
index 9b0826949..13885c2cc 100644
--- a/apps/ops/templates/ops/celery_task_log.html
+++ b/apps/ops/templates/ops/celery_task_log.html
@@ -2,38 +2,25 @@
term.js
+
+
-