Commit 8e9b3f13 authored by ibuler's avatar ibuler

[Update] 修改permission actions

parents 48ba1993 320b17c8
......@@ -112,12 +112,16 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
is_root = False
def get_queryset(self):
self.check_need_refresh_nodes()
node_key = self.request.query_params.get('key')
util = NodeUtil()
# 是否包含自己
with_self = False
if not node_key:
node_key = Node.root().key
with_self = True
self.node = util.get_node_by_key(node_key)
queryset = self.node.get_children(with_self=True)
queryset = self.node.get_children(with_self=with_self)
queryset = [node.as_tree_node() for node in queryset]
queryset = sorted(queryset)
return queryset
......@@ -133,14 +137,11 @@ class NodeChildrenAsTreeApi(generics.ListAPIView):
def filter_queryset(self, queryset):
queryset = self.filter_assets(queryset)
queryset = self.filter_refresh_nodes(queryset)
return queryset
def filter_refresh_nodes(self, queryset):
def check_need_refresh_nodes(self):
if self.request.query_params.get('refresh', '0') == '1':
Node.expire_nodes_assets_amount()
Node.expire_nodes_full_value()
return queryset
Node.refresh_nodes()
class NodeChildrenApi(mixins.ListModelMixin, generics.CreateAPIView):
......
......@@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
from common.utils import get_logger
from orgs.mixins import OrgModelForm
from ..models import Asset, Protocol
from ..models import Asset, Protocol, Node
logger = get_logger(__file__)
......@@ -33,6 +33,12 @@ class ProtocolForm(forms.ModelForm):
class AssetCreateForm(OrgModelForm):
PROTOCOL_CHOICES = Protocol.PROTOCOL_CHOICES
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.data:
nodes_field = self.fields['nodes']
nodes_field._queryset = Node.get_queryset()
class Meta:
model = Asset
fields = [
......
......@@ -186,9 +186,6 @@ class FullValueMixin:
def expire_nodes_full_value(cls, nodes=None):
key = cls._full_value_cache_key.format('*')
cache.delete_pattern(key+'*')
from ..utils import NodeUtil
util = NodeUtil()
util.set_full_value()
class AssetsAmountMixin:
......@@ -216,7 +213,7 @@ class AssetsAmountMixin:
def assets_amount(self, value):
self._assets_amount = value
cache_key = self._assets_amount_cache_key.format(self.key)
cache.set(cache_key, value, 3600 * 24)
cache.set(cache_key, value)
def expire_assets_amount(self):
ancestor_keys = self.get_ancestor_keys(with_self=True)
......@@ -226,11 +223,15 @@ class AssetsAmountMixin:
@classmethod
def expire_nodes_assets_amount(cls, nodes=None):
from ..utils import NodeUtil
key = cls._assets_amount_cache_key.format('*')
cache.delete_pattern(key)
@classmethod
def refresh_nodes(cls):
from ..utils import NodeUtil
util = NodeUtil(with_assets_amount=True)
util.set_assets_amount()
util.set_full_value()
class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
......@@ -375,9 +376,7 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
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,
......@@ -386,7 +385,12 @@ class Node(OrgModelMixin, FamilyMixin, FullValueMixin, AssetsAmountMixin):
'isParent': True,
'open': self.is_root(),
'meta': {
'node': node_serializer.data,
'node': {
"id": self.id,
"name": self.name,
"value": self.value,
"key": self.key,
},
'type': 'node'
}
}
......
# -*- coding: utf-8 -*-
from rest_framework import serializers
from django.utils.translation import ugettext as _
from orgs.mixins import BulkOrgResourceModelSerializer
from ..models import Asset, Node
......@@ -25,11 +26,11 @@ class NodeSerializer(BulkOrgResourceModelSerializer):
def validate_value(self, data):
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 data in values:
children = instance.parent.get_children()
children_values = [node.value for node in children if node != instance]
if data in children_values:
raise serializers.ValidationError(
'The same level node name cannot be the same'
_('The same level node name cannot be the same')
)
return data
......
......@@ -67,6 +67,7 @@ function initTable2() {
columns: [
{data: "id"}, {data: "hostname" }, {data: "ip" }
],
lengthMenu: [[10, 25, 50], [10, 25, 50]],
pageLength: 10
};
asset_table2 = jumpserver.initServerSideDataTable(options);
......
{% load static %}
{% load i18n %}
<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
{# <link href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet">#}
<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
<style type="text/css">
div#rMenu {
position: absolute;
visibility: hidden;
text-align: left;
{#top: 100%;#}
top: 0;
left: 0;
z-index: 999;
{#float: left;#}
padding: 0 0;
margin: 2px 0 0;
list-style: none;
background-clip: padding-box;
}
.dataTables_wrapper .dataTables_processing {
opacity: .9;
border: none;
}
div#rMenu li{
margin: 1px 0;
cursor: pointer;
list-style: none outside none;
}
.dropdown a:hover {
background-color: #f1f1f1
}
</style>
<div class="ibox float-e-margins">
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
<div class="file-manager" id="tree-node-id">
<div id="{% block treeID %}nodeTree{% endblock %}" class="ztree">
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
<div id="rMenu">
<ul class="dropdown-menu menu-actions">
<li class="divider"></li>
<li id="m_create" tabindex="-1" onclick="addTreeNode();"><a><i class="fa fa-plus-square-o"></i> {% trans 'Add node' %}</a></li>
<li id="m_del" tabindex="-1" onclick="editTreeNode();"><a><i class="fa fa-pencil-square-o"></i> {% trans 'Rename node' %}</a></li>
<li id="m_del" tabindex="-1" onclick="removeTreeNode();"><a><i class="fa fa-minus-square"></i> {% trans 'Delete node' %}</a></li>
</ul>
</div>
<script>
var zTree, rMenu = null;
var current_node_id = null;
var current_node = null;
var showMenu = false;
var treeUrl = '{% url 'api-assets:node-children-tree' %}?assets=0';
// options:
// {
// "onSelected": func,
// "showAssets": false,
// "beforeAsync": func()
// "showMenu": false,
// "otherMenu": "",
// "showAssets": false,
// }
function initNodeTree(options) {
var setting = {
view: {
dblClickExpand: false,
showLine: true
},
data: {
simpleData: {
enable: true
}
},
async: {
enable: true,
url: treeUrl,
autoParam: ["id=key", "name=n", "level=lv"],
type: 'get'
},
edit: {
enable: true,
showRemoveBtn: false,
showRenameBtn: false,
drag: {
isCopy: true,
isMove: true
}
},
callback: {
onRightClick: OnRightClick,
beforeClick: beforeClick,
onRename: onRename,
onSelected: options.onSelected || defaultCallback("On selected"),
beforeDrag: beforeDrag,
onDrag: onDrag,
beforeDrop: beforeDrop,
onDrop: onDrop,
beforeAsync: options.beforeAsync || defaultCallback("Before async")
}
};
if (options.showAssets) {
treeUrl = setUrlParam(treeUrl, 'assets', '1')
}
$.get(treeUrl, function(data, status){
zNodes = data;
zTree = $.fn.zTree.init($("#nodeTree"), setting, zNodes);
rootNodeAddDom(zTree, function () {
treeUrl = setUrlParam(treeUrl, 'refresh', '1');
initTree();
treeUrl = setUrlParam(treeUrl, 'refresh', '0')
});
});
if (options.showMenu) {
showMenu = true;
rMenu = $("#rMenu");
}
if (options.otherMenu) {
$(".menu-actions").append(options.otherMenu)
}
return zTree
}
function addTreeNode() {
hideRMenu();
var parentNode = zTree.getSelectedNodes()[0];
if (!parentNode){
return
}
var url = "{% url 'api-assets:node-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", parentNode.meta.node.id);
$.post(url, {}, function (data, status){
if (status === "success") {
var newNode = {
id: data["key"],
name: data["value"],
pId: parentNode.id,
meta: {
"node": data
}
};
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' %}")
}
});
}
function removeTreeNode() {
hideRMenu();
var current_node = zTree.getSelectedNodes()[0];
if (!current_node){
return
}
if (current_node.children && current_node.children.length > 0) {
toastr.error("{% trans 'Have child node, cancel' %}");
} else if (current_node.meta.node.assets_amount !== 0) {
toastr.error("{% trans 'Have assets, cancel' %}");
} else {
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
$.ajax({
url: url,
method: "DELETE",
success: function () {
zTree.removeNode(current_node);
}
});
}
}
function editTreeNode() {
hideRMenu();
var current_node = zTree.getSelectedNodes()[0];
if (!current_node){
return
}
if (current_node) {
current_node.name = current_node.meta.node.value;
}
zTree.editName(current_node);
}
function OnRightClick(event, treeId, treeNode) {
if (!showMenu) {
return
}
if (!treeNode && event.target.tagName.toLowerCase() !== "button" && $(event.target).parents("a").length === 0) {
zTree.cancelSelectedNode();
showRMenu("root", event.clientX, event.clientY);
} else if (treeNode && !treeNode.noR) {
zTree.selectNode(treeNode);
showRMenu("node", event.clientX, event.clientY);
}
}
function showRMenu(type, x, y) {
var offset = $("#tree-node-id").offset();
x -= offset.left;
y -= offset.top;
x += document.body.scrollLeft;
y += document.body.scrollTop + document.documentElement.scrollTop;
rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"});
$("#rMenu ul").show();
$("body").bind("mousedown", onBodyMouseDown);
}
function beforeClick(treeId, treeNode, clickFlag) {
return true;
}
function hideRMenu() {
if (rMenu) rMenu.css({"visibility": "hidden"});
$("body").unbind("mousedown", onBodyMouseDown);
}
function onBodyMouseDown(event){
if (!(event.target.id === "rMenu" || $(event.target).parents("#rMenu").length>0)) {
rMenu.css({"visibility" : "hidden"});
}
}
function onRename(event, treeId, treeNode, isCancel){
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
var data = {"value": treeNode.name};
if (isCancel){
return
}
APIUpdateAttr({
url: url,
body: JSON.stringify(data),
method: "PATCH",
success_message: "{% trans 'Rename success' %}",
success: function () {
treeNode.name = treeNode.name + ' (' + treeNode.meta.node.assets_amount + ')';
zTree.updateNode(treeNode);
console.log("Success: " + treeNode.name)
}
})
}
function beforeDrag() {
return true
}
function beforeDrop(treeId, treeNodes, targetNode, moveType) {
var treeNodesNames = [];
$.each(treeNodes, function (index, value) {
treeNodesNames.push(value.name);
});
var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.name + "` 下吗?";
return confirm(msg);
}
function onDrag(event, treeId, treeNodes) {
}
function onDrop(event, treeId, treeNodes, targetNode, moveType) {
var treeNodesIds = [];
$.each(treeNodes, function (index, value) {
treeNodesIds.push(value.meta.node.id);
});
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.meta.node.id);
var body = {nodes: treeNodesIds};
APIUpdateAttr({
url: the_url,
method: "PUT",
body: JSON.stringify(body)
})
}
function defaultCallback(action) {
function logging() {
console.log(action)
}
return logging
}
$(document).ready(function () {
})
.on('click', '.btn-refresh-hardware', function () {
var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}";
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
function success(data) {
rMenu.css({"visibility" : "hidden"});
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')
}
APIUpdateAttr({
url: the_url,
method: "GET",
success: success,
flash_message: false
});
})
.on('click', '.btn-test-connective', function () {
var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}";
if (!current_node_id) {
return null;
}
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
function success(data) {
rMenu.css({"visibility" : "hidden"});
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')
}
APIUpdateAttr({
url: the_url,
method: "GET",
success: success,
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', '1');
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-test-connective', function () {
hideRMenu();
})
.on('click', '#menu_refresh_assets_amount', function () {
hideRMenu();
var url = "{% url 'api-assets:refresh-assets-amount' %}";
APIUpdateAttr({
'url': url,
'method': 'GET'
});
window.location.reload();
})
</script>
\ No newline at end of file
......@@ -49,15 +49,7 @@
<div class="wrapper wrapper-content">
<div class="row">
<div class="col-lg-3" id="split-left" style="padding-left: 3px">
<div class="ibox float-e-margins">
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
<div class="file-manager ">
<div id="assetTree" class="ztree">
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
{% include 'assets/_node_tree.html' %}
</div>
<div class="col-lg-9 animated fadeInRight" id="split-right">
<div class="tree-toggle">
......@@ -132,26 +124,7 @@
</div>
</div>
<div id="rMenu">
<ul class="dropdown-menu">
<li class="divider"></li>
<li id="m_create" tabindex="-1" onclick="addTreeNode();"><a><i class="fa fa-plus-square-o"></i> {% trans 'Add node' %}</a></li>
<li id="m_del" tabindex="-1" onclick="editTreeNode();"><a><i class="fa fa-pencil-square-o"></i> {% trans 'Rename node' %}</a></li>
<li id="m_del" tabindex="-1" onclick="removeTreeNode();"><a><i class="fa fa-minus-square"></i> {% trans 'Delete node' %}</a></li>
<li class="divider"></li>
<li id="menu_asset_add" class="btn-add-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-copy"></i> {% trans 'Add assets to node' %}</a></li>
<li id="menu_asset_move" class="btn-move-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-cut"></i> {% trans 'Move assets to node' %}</a></li>
<li class="divider"></li>
<li id="menu_refresh_hardware_info" class="btn-refresh-hardware" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh node hardware info' %}</a></li>
<li id="menu_test_connective" class="btn-test-connective" tabindex="-1"><a><i class="fa fa-chain"></i> {% trans 'Test node connective' %}</a></li>
<li class="divider"></li>
<li id="menu_refresh_assets_amount" class="btn-refresh-assets-amount" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh all node assets amount' %}</a></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_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>
</div>
{% include 'assets/_node_tree.html' %}
{% include 'assets/_asset_update_modal.html' %}
{% include 'assets/_asset_import_modal.html' %}
{% include 'assets/_asset_list_modal.html' %}
......@@ -159,11 +132,11 @@
{% block custom_foot_js %}
<script>
var zTree, rMenu, asset_table, show = 0;
var asset_table, show = 0;
var update_node_action = "";
var current_node_id = null;
var current_node = null;
var testDatetime = "{% trans 'Test datetime: ' %}";
function initTable() {
var options = {
ele: $('#asset_list_table'),
......@@ -209,239 +182,24 @@ function initTable() {
asset_table = jumpserver.initServerSideDataTable(options);
return asset_table
}
function addTreeNode() {
hideRMenu();
var parentNode = zTree.getSelectedNodes()[0];
if (!parentNode){
return
}
var url = "{% url 'api-assets:node-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", parentNode.meta.node.id);
$.post(url, {}, function (data, status){
if (status === "success") {
var newNode = {
id: data["key"],
name: data["value"],
pId: parentNode.id,
meta: {
"node": data
}
};
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' %}")
}
});
}
function removeTreeNode() {
hideRMenu();
var current_node = zTree.getSelectedNodes()[0];
if (!current_node){
return
}
if (current_node.children && current_node.children.length > 0) {
toastr.error("{% trans 'Have child node, cancel' %}");
} else if (current_node.meta.node.assets_amount !== 0) {
toastr.error("{% trans 'Have assets, cancel' %}");
} else {
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
$.ajax({
url: url,
method: "DELETE",
success: function () {
zTree.removeNode(current_node);
}
});
}
}
function editTreeNode() {
hideRMenu();
var current_node = zTree.getSelectedNodes()[0];
if (!current_node){
return
}
if (current_node) {
current_node.name = current_node.meta.node.value;
}
zTree.editName(current_node);
}
function OnRightClick(event, treeId, treeNode) {
if (!treeNode && event.target.tagName.toLowerCase() !== "button" && $(event.target).parents("a").length === 0) {
zTree.cancelSelectedNode();
showRMenu("root", event.clientX, event.clientY);
} else if (treeNode && !treeNode.noR) {
zTree.selectNode(treeNode);
showRMenu("node", event.clientX, event.clientY);
}
}
function showRMenu(type, x, y) {
$("#rMenu ul").show();
x -= 220;
x += document.body.scrollLeft;
y += document.body.scrollTop+document.documentElement.scrollTop;
rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"});
$("body").bind("mousedown", onBodyMouseDown);
}
function beforeClick(treeId, treeNode, clickFlag) {
return true;
}
function hideRMenu() {
if (rMenu) rMenu.css({"visibility": "hidden"});
$("body").unbind("mousedown", onBodyMouseDown);
}
function onBodyMouseDown(event){
if (!(event.target.id === "rMenu" || $(event.target).parents("#rMenu").length>0)) {
rMenu.css({"visibility" : "hidden"});
}
}
function onRename(event, treeId, treeNode, isCancel){
var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
var data = {"value": treeNode.name};
if (isCancel){
return
}
APIUpdateAttr({
url: url,
body: JSON.stringify(data),
method: "PATCH",
success_message: "{% trans 'Rename success' %}",
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) {
current_node = treeNode;
current_node_id = treeNode.meta.node.id;
zTree.expandNode(current_node, true);
var url = asset_table.ajax.url();
url = setUrlParam(url, "node_id", current_node_id);
url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset'));
setCookie('node_selected', treeNode.node_id);
asset_table.ajax.url(url);
asset_table.ajax.reload();
}
function selectQueryNode() {
// TODO: 是否应该添加
// 暂时忽略之前选中的内容
return
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("node_id", node_id, null);
if (node){
zTree.selectNode(node[0]);
}
}
function beforeDrag() {
return true
}
function beforeDrop(treeId, treeNodes, targetNode, moveType) {
var treeNodesNames = [];
$.each(treeNodes, function (index, value) {
treeNodesNames.push(value.name);
});
var msg = "你想移动节点: `" + treeNodesNames.join(",") + "` 到 `" + targetNode.name + "` 下吗?";
return confirm(msg);
}
function onDrag(event, treeId, treeNodes) {
}
function onDrop(event, treeId, treeNodes, targetNode, moveType) {
var treeNodesIds = [];
$.each(treeNodes, function (index, value) {
treeNodesIds.push(value.meta.node.id);
});
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.meta.node.id);
var body = {nodes: treeNodesIds};
APIUpdateAttr({
url: the_url,
method: "PUT",
body: JSON.stringify(body)
function initTree() {
initNodeTree({
onSelected: onNodeSelected,
showMenu: true,
otherMenu: `
<li class="divider"></li>
<li id="menu_asset_add" class="btn-add-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-copy"></i> {% trans 'Add assets to node' %}</a></li>
<li id="menu_asset_move" class="btn-move-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a><i class="fa fa-cut"></i> {% trans 'Move assets to node' %}</a></li>
<li class="divider"></li>
<li id="menu_refresh_hardware_info" class="btn-refresh-hardware" tabindex="-1"><a><i class="fa fa-refresh"></i> {% trans 'Refresh node hardware info' %}</a></li>
<li id="menu_test_connective" class="btn-test-connective" tabindex="-1"><a><i class="fa fa-chain"></i> {% trans 'Test node connective' %}</a></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_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>
`
})
}
function initTree() {
if (zTree) {
return
}
var url = '{% url 'api-assets:node-children-tree' %}?assets=0&all=';
var showCurrentAsset = getCookie('show_current_asset');
if (!showCurrentAsset) {
url += '1'
}
var setting = {
view: {
dblClickExpand: false,
showLine: true
},
data: {
simpleData: {
enable: true
}
},
async: {
enable: true,
url: url,
autoParam: ["id=key", "name=n", "level=lv"],
type: 'get'
},
edit: {
enable: true,
showRemoveBtn: false,
showRenameBtn: false,
drag: {
isCopy: true,
isMove: true
}
},
callback: {
onRightClick: OnRightClick,
beforeClick: beforeClick,
onRename: onRename,
onSelected: onSelected,
beforeDrag: beforeDrag,
onDrag: onDrag,
beforeDrop: beforeDrop,
onDrop: onDrop
}
};
var zNodes = [];
zTree = $.fn.zTree.init($("#assetTree"), setting, zNodes);
rMenu = $("#rMenu");
}
function toggle() {
if (show === 0) {
......@@ -458,6 +216,18 @@ function toggle() {
}
}
function onNodeSelected(event, treeNode) {
current_node = treeNode;
current_node_id = treeNode.meta.node.id;
zTree.expandNode(current_node, true);
var url = asset_table.ajax.url();
url = setUrlParam(url, "node_id", current_node_id);
url = setUrlParam(url, "show_current_asset", getCookie('show_current_asset'));
setCookie('node_selected', treeNode.node_id);
asset_table.ajax.url(url);
asset_table.ajax.reload();
}
$(document).ready(function(){
initTable();
initTree();
......@@ -555,69 +325,7 @@ $(document).ready(function(){
}
window.open(url, '_self');
})
.on('click', '.btn-refresh-hardware', function () {
var url = "{% url 'api-assets:node-refresh-hardware-info' pk=DEFAULT_PK %}";
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
function success(data) {
rMenu.css({"visibility" : "hidden"});
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')
}
APIUpdateAttr({
url: the_url,
method: "GET",
success: success,
flash_message: false
});
})
.on('click', '.btn-test-connective', function () {
var url = "{% url 'api-assets:node-test-connective' pk=DEFAULT_PK %}";
if (!current_node_id) {
return null;
}
var the_url = url.replace("{{ DEFAULT_PK }}", current_node_id);
function success(data) {
rMenu.css({"visibility" : "hidden"});
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')
}
APIUpdateAttr({
url: the_url,
method: "GET",
success: success,
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', '1');
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-test-connective', function () {
hideRMenu();
})
.on('click', '#menu_refresh_assets_amount', function () {
hideRMenu();
var url = "{% url 'api-assets:refresh-assets-amount' %}";
APIUpdateAttr({
'url': url,
'method': 'GET'
});
window.location.reload();
})
.on('click', '.btn_asset_delete', function () {
var $this = $(this);
var $data_table = $("#asset_list_table").DataTable();
......
# ~*~ coding: utf-8 ~*~
#
import time
from django.db.models import Prefetch
from common.utils import get_object_or_none, get_logger
......@@ -56,9 +57,11 @@ class NodeUtil:
def get_all_nodes(self):
all_nodes = Node.objects.all()
if self.with_assets_amount:
now = time.time()
all_nodes = all_nodes.prefetch_related(
Prefetch('assets', queryset=Asset.objects.all().only('id'))
)
all_nodes = list(all_nodes)
for node in all_nodes:
node._assets = set(node.assets.all())
all_nodes = sorted(all_nodes, key=self.sorted_by)
......
......@@ -130,16 +130,13 @@ def get_short_uuid_str():
def is_uuid(seq):
if isinstance(seq, str):
if UUID_PATTERN.match(seq):
return True
else:
return False
else:
for s in seq:
if not is_uuid(s):
return False
if isinstance(seq, uuid.UUID):
return True
elif isinstance(seq, str) and UUID_PATTERN.match(seq):
return True
elif isinstance(seq, (list, tuple)):
all([is_uuid(x) for x in seq])
return False
def get_request_ip(request):
......
......@@ -399,7 +399,7 @@ REST_FRAMEWORK = {
'ORDERING_PARAM': "order",
'SEARCH_PARAM': "search",
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S %z',
'DATETIME_INPUT_FORMATS': ['%Y-%m-%d %H:%M:%S %z'],
'DATETIME_INPUT_FORMATS': ['iso-8601', '%Y-%m-%d %H:%M:%S %z'],
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
# 'PAGE_SIZE': 15
}
......
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-24 21:38+0800\n"
"POT-Creation-Date: 2019-06-28 20:08+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
......@@ -76,8 +76,8 @@ msgstr "运行参数"
#: applications/templates/applications/remote_app_list.html:22
#: applications/templates/applications/user_remote_app_list.html:18
#: assets/forms/domain.py:15 assets/forms/label.py:13
#: assets/models/asset.py:298 assets/models/authbook.py:24
#: assets/serializers/admin_user.py:35 assets/serializers/asset_user.py:106
#: assets/models/asset.py:292 assets/models/authbook.py:24
#: assets/serializers/admin_user.py:35 assets/serializers/asset_user.py:89
#: assets/serializers/system_user.py:29
#: assets/templates/assets/admin_user_list.html:49
#: assets/templates/assets/domain_detail.html:60
......@@ -86,10 +86,10 @@ msgstr "运行参数"
#: assets/templates/assets/system_user_list.html:55 audits/models.py:19
#: audits/templates/audits/ftp_log_list.html:41
#: audits/templates/audits/ftp_log_list.html:71
#: perms/forms/asset_permission.py:46 perms/models/asset_permission.py:37
#: perms/forms/asset_permission.py:47 perms/models/asset_permission.py:53
#: perms/templates/perms/asset_permission_create_update.html:45
#: perms/templates/perms/asset_permission_list.html:56
#: perms/templates/perms/asset_permission_list.html:125
#: perms/templates/perms/asset_permission_list.html:48
#: perms/templates/perms/asset_permission_list.html:117
#: terminal/backends/command/models.py:13 terminal/models.py:155
#: terminal/templates/terminal/command_list.html:40
#: terminal/templates/terminal/command_list.html:73
......@@ -115,12 +115,12 @@ msgstr "资产"
#: assets/models/user.py:160 assets/templates/assets/user_asset_list.html:172
#: audits/models.py:20 audits/templates/audits/ftp_log_list.html:49
#: audits/templates/audits/ftp_log_list.html:72
#: perms/forms/asset_permission.py:52 perms/models/asset_permission.py:39
#: perms/models/asset_permission.py:59
#: perms/forms/asset_permission.py:53 perms/models/asset_permission.py:55
#: perms/models/asset_permission.py:76
#: perms/templates/perms/asset_permission_detail.html:140
#: perms/templates/perms/asset_permission_list.html:58
#: perms/templates/perms/asset_permission_list.html:79
#: perms/templates/perms/asset_permission_list.html:131 templates/_nav.html:25
#: perms/templates/perms/asset_permission_list.html:50
#: perms/templates/perms/asset_permission_list.html:71
#: perms/templates/perms/asset_permission_list.html:123 templates/_nav.html:25
#: terminal/backends/command/models.py:14 terminal/models.py:156
#: terminal/templates/terminal/command_list.html:48
#: terminal/templates/terminal/command_list.html:74
......@@ -135,7 +135,7 @@ msgstr "系统用户"
#: applications/templates/applications/remote_app_list.html:20
#: applications/templates/applications/user_remote_app_list.html:16
#: assets/forms/domain.py:73 assets/forms/user.py:84 assets/forms/user.py:148
#: assets/models/asset.py:70 assets/models/base.py:27
#: assets/models/asset.py:64 assets/models/base.py:27
#: assets/models/cluster.py:18 assets/models/cmd_filter.py:20
#: assets/models/domain.py:20 assets/models/group.py:20
#: assets/models/label.py:18 assets/templates/assets/admin_user_detail.html:56
......@@ -149,11 +149,11 @@ msgstr "系统用户"
#: assets/templates/assets/system_user_detail.html:58
#: assets/templates/assets/system_user_list.html:51 ops/models/adhoc.py:37
#: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:27
#: orgs/models.py:12 perms/models/asset_permission.py:22
#: orgs/models.py:11 perms/models/asset_permission.py:22
#: perms/models/base.py:35
#: perms/templates/perms/asset_permission_detail.html:62
#: perms/templates/perms/asset_permission_list.html:53
#: perms/templates/perms/asset_permission_list.html:72
#: perms/templates/perms/asset_permission_list.html:45
#: perms/templates/perms/asset_permission_list.html:64
#: perms/templates/perms/asset_permission_user.html:54
#: perms/templates/perms/remote_app_permission_detail.html:62
#: perms/templates/perms/remote_app_permission_list.html:14
......@@ -167,7 +167,7 @@ msgstr "系统用户"
#: settings/templates/settings/terminal_setting.html:105 terminal/models.py:22
#: terminal/models.py:258 terminal/templates/terminal/terminal_detail.html:43
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
#: users/models/user.py:63 users/templates/users/_select_user_modal.html:13
#: users/models/user.py:64 users/templates/users/_select_user_modal.html:13
#: users/templates/users/user_detail.html:63
#: users/templates/users/user_group_detail.html:55
#: users/templates/users/user_group_list.html:35
......@@ -206,7 +206,7 @@ msgstr "参数"
#: applications/models/remote_app.py:43
#: applications/templates/applications/remote_app_detail.html:77
#: assets/models/asset.py:130 assets/models/base.py:35
#: assets/models/asset.py:124 assets/models/base.py:35
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:25
#: assets/models/cmd_filter.py:58 assets/models/group.py:21
#: assets/templates/assets/admin_user_detail.html:68
......@@ -214,11 +214,11 @@ msgstr "参数"
#: assets/templates/assets/cmd_filter_detail.html:77
#: assets/templates/assets/domain_detail.html:72
#: assets/templates/assets/system_user_detail.html:100
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15
#: perms/models/asset_permission.py:62 perms/models/base.py:41
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:14
#: perms/models/asset_permission.py:79 perms/models/base.py:41
#: perms/templates/perms/asset_permission_detail.html:98
#: perms/templates/perms/remote_app_permission_detail.html:90
#: users/models/user.py:104 users/serializers/v1.py:73
#: users/models/user.py:105 users/serializers/v1.py:99
#: users/templates/users/user_detail.html:111
#: xpack/plugins/change_auth_plan/models.py:106
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113
......@@ -230,7 +230,7 @@ msgstr "创建者"
# msgstr "创建者"
#: applications/models/remote_app.py:46
#: applications/templates/applications/remote_app_detail.html:73
#: assets/models/asset.py:131 assets/models/base.py:33
#: assets/models/asset.py:125 assets/models/base.py:33
#: assets/models/cluster.py:26 assets/models/domain.py:23
#: assets/models/group.py:22 assets/models/label.py:25
#: assets/templates/assets/admin_user_detail.html:64
......@@ -238,7 +238,7 @@ msgstr "创建者"
#: assets/templates/assets/domain_detail.html:68
#: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:64
#: orgs/models.py:16 perms/models/asset_permission.py:63
#: orgs/models.py:15 perms/models/asset_permission.py:80
#: perms/models/base.py:42
#: perms/templates/perms/asset_permission_detail.html:94
#: perms/templates/perms/remote_app_permission_detail.html:86
......@@ -258,7 +258,7 @@ msgstr "创建日期"
#: applications/templates/applications/remote_app_detail.html:81
#: applications/templates/applications/remote_app_list.html:24
#: applications/templates/applications/user_remote_app_list.html:20
#: assets/models/asset.py:132 assets/models/base.py:32
#: assets/models/asset.py:126 assets/models/base.py:32
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:22
#: assets/models/cmd_filter.py:55 assets/models/domain.py:21
#: assets/models/domain.py:53 assets/models/group.py:23
......@@ -274,13 +274,13 @@ msgstr "创建日期"
#: assets/templates/assets/system_user_detail.html:104
#: assets/templates/assets/system_user_list.html:59
#: assets/templates/assets/user_asset_list.html:175 ops/models/adhoc.py:43
#: orgs/models.py:17 perms/models/asset_permission.py:64
#: orgs/models.py:16 perms/models/asset_permission.py:81
#: perms/models/base.py:43
#: perms/templates/perms/asset_permission_detail.html:102
#: perms/templates/perms/remote_app_permission_detail.html:94
#: settings/models.py:34 terminal/models.py:32
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
#: users/models/user.py:96 users/templates/users/user_detail.html:127
#: users/models/user.py:97 users/templates/users/user_detail.html:127
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:37
#: users/templates/users/user_profile.html:134
......@@ -350,7 +350,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:82
#: assets/templates/assets/asset_list.html:125
#: assets/templates/assets/asset_list.html:117
#: assets/templates/assets/cmd_filter_create_update.html:16
#: assets/templates/assets/cmd_filter_rule_create_update.html:41
#: assets/templates/assets/domain_create_update.html:17
......@@ -416,8 +416,8 @@ msgstr "详情"
#: assets/templates/assets/admin_user_list.html:29
#: assets/templates/assets/admin_user_list.html:114
#: assets/templates/assets/asset_detail.html:27
#: assets/templates/assets/asset_list.html:86
#: assets/templates/assets/asset_list.html:196
#: assets/templates/assets/asset_list.html:78
#: assets/templates/assets/asset_list.html:169
#: assets/templates/assets/cmd_filter_detail.html:29
#: assets/templates/assets/cmd_filter_list.html:58
#: assets/templates/assets/cmd_filter_rule_list.html:86
......@@ -430,7 +430,7 @@ msgstr "详情"
#: assets/templates/assets/system_user_list.html:33
#: assets/templates/assets/system_user_list.html:119 audits/models.py:33
#: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:181
#: perms/templates/perms/asset_permission_list.html:173
#: perms/templates/perms/remote_app_permission_detail.html:30
#: perms/templates/perms/remote_app_permission_list.html:59
#: terminal/templates/terminal/terminal_detail.html:16
......@@ -459,7 +459,7 @@ msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:115
#: assets/templates/assets/asset_detail.html:31
#: assets/templates/assets/asset_list.html:197
#: assets/templates/assets/asset_list.html:170
#: assets/templates/assets/cmd_filter_detail.html:33
#: assets/templates/assets/cmd_filter_list.html:59
#: assets/templates/assets/cmd_filter_rule_list.html:87
......@@ -472,7 +472,7 @@ msgstr "更新"
#: assets/templates/assets/system_user_list.html:120 audits/models.py:34
#: ops/templates/ops/task_list.html:64
#: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:182
#: perms/templates/perms/asset_permission_list.html:174
#: perms/templates/perms/remote_app_permission_detail.html:34
#: perms/templates/perms/remote_app_permission_list.html:60
#: settings/templates/settings/terminal_setting.html:93
......@@ -517,7 +517,7 @@ msgstr "创建远程应用"
#: assets/models/cmd_filter.py:54
#: assets/templates/assets/_asset_user_list.html:20
#: assets/templates/assets/admin_user_list.html:54
#: assets/templates/assets/asset_list.html:108
#: assets/templates/assets/asset_list.html:100
#: assets/templates/assets/cmd_filter_list.html:28
#: assets/templates/assets/cmd_filter_rule_list.html:63
#: assets/templates/assets/domain_gateway_list.html:73
......@@ -529,11 +529,11 @@ msgstr "创建远程应用"
#: audits/templates/audits/operate_log_list.html:67
#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64
#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:34
#: perms/forms/asset_permission.py:55 perms/models/asset_permission.py:26
#: perms/models/asset_permission.py:40
#: perms/forms/asset_permission.py:56 perms/models/asset_permission.py:26
#: perms/models/asset_permission.py:57
#: perms/templates/perms/asset_permission_create_update.html:50
#: perms/templates/perms/asset_permission_list.html:60
#: perms/templates/perms/asset_permission_list.html:134
#: perms/templates/perms/asset_permission_list.html:52
#: perms/templates/perms/asset_permission_list.html:126
#: perms/templates/perms/remote_app_permission_list.html:19
#: settings/templates/settings/terminal_setting.html:85
#: settings/templates/settings/terminal_setting.html:107
......@@ -552,6 +552,7 @@ msgstr "动作"
#: applications/templates/applications/user_remote_app_list.html:57
#: assets/templates/assets/user_asset_list.html:100 perms/const.py:19
#: perms/models/asset_permission.py:45
msgid "Connect"
msgstr "连接"
......@@ -586,15 +587,15 @@ msgstr "%(hostname)s %(action)s成功"
msgid "Please select assets that need to be updated"
msgstr "请选择需要更新的资产"
#: assets/api/node.py:60
#: assets/api/node.py:61
msgid "You can't update the root node name"
msgstr "不能修改根节点名称"
#: assets/api/node.py:285
#: assets/api/node.py:281
msgid "Update node asset hardware information: {}"
msgstr "更新节点资产硬件信息: {}"
#: assets/api/node.py:299
#: assets/api/node.py:295
msgid "Test if the assets under the node are connectable: {}"
msgstr "测试节点下资产是否可连接: {}"
......@@ -606,7 +607,7 @@ msgstr "不可达"
#: assets/const.py:78 assets/models/utils.py:44
#: assets/templates/assets/admin_user_list.html:50
#: assets/templates/assets/asset_list.html:107
#: assets/templates/assets/asset_list.html:99
#: assets/templates/assets/system_user_list.html:56
#: users/templates/users/user_group_granted_asset.html:47
msgid "Reachable"
......@@ -617,16 +618,16 @@ msgstr "可连接"
msgid "Unknown"
msgstr "未知"
#: assets/forms/asset.py:45 assets/models/asset.py:101
#: assets/models/user.py:107 assets/templates/assets/asset_detail.html:194
#: assets/forms/asset.py:51 assets/models/asset.py:95 assets/models/user.py:107
#: assets/templates/assets/asset_detail.html:194
#: assets/templates/assets/asset_detail.html:202
#: assets/templates/assets/system_user_assets.html:83
#: perms/models/asset_permission.py:38
#: perms/models/asset_permission.py:54
#: xpack/plugins/change_auth_plan/models.py:72
msgid "Nodes"
msgstr "节点"
#: assets/forms/asset.py:48 assets/forms/asset.py:83 assets/models/asset.py:105
#: assets/forms/asset.py:54 assets/forms/asset.py:89 assets/models/asset.py:99
#: assets/models/cluster.py:19 assets/models/user.py:65
#: assets/templates/assets/asset_detail.html:80 templates/_nav.html:24
#: xpack/plugins/cloud/models.py:124
......@@ -635,16 +636,16 @@ msgstr "节点"
msgid "Admin user"
msgstr "管理用户"
#: assets/forms/asset.py:51 assets/forms/asset.py:86 assets/forms/asset.py:125
#: assets/forms/asset.py:57 assets/forms/asset.py:92 assets/forms/asset.py:131
#: assets/templates/assets/asset_create.html:48
#: assets/templates/assets/asset_create.html:50
#: assets/templates/assets/asset_list.html:93
#: assets/templates/assets/asset_list.html:85
#: assets/templates/assets/user_asset_list.html:33
#: xpack/plugins/orgs/templates/orgs/org_list.html:20
msgid "Label"
msgstr "标签"
#: assets/forms/asset.py:54 assets/forms/asset.py:89 assets/models/asset.py:100
#: assets/forms/asset.py:60 assets/forms/asset.py:95 assets/models/asset.py:94
#: assets/models/domain.py:26 assets/models/domain.py:52
#: assets/templates/assets/asset_detail.html:84
#: assets/templates/assets/user_asset_list.html:173
......@@ -652,14 +653,14 @@ msgstr "标签"
msgid "Domain"
msgstr "网域"
#: assets/forms/asset.py:58 assets/forms/asset.py:80 assets/forms/asset.py:93
#: assets/forms/asset.py:128 assets/models/node.py:31
#: assets/forms/asset.py:64 assets/forms/asset.py:86 assets/forms/asset.py:99
#: assets/forms/asset.py:134 assets/models/node.py:248
#: assets/templates/assets/asset_create.html:42
#: perms/forms/asset_permission.py:49 perms/forms/asset_permission.py:59
#: perms/models/asset_permission.py:57
#: perms/templates/perms/asset_permission_list.html:57
#: perms/templates/perms/asset_permission_list.html:78
#: perms/templates/perms/asset_permission_list.html:128
#: perms/forms/asset_permission.py:50 perms/forms/asset_permission.py:60
#: perms/models/asset_permission.py:74
#: perms/templates/perms/asset_permission_list.html:49
#: perms/templates/perms/asset_permission_list.html:70
#: perms/templates/perms/asset_permission_list.html:120
#: xpack/plugins/change_auth_plan/forms.py:115
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:55
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:15
......@@ -669,7 +670,7 @@ msgstr "网域"
msgid "Node"
msgstr "节点"
#: assets/forms/asset.py:62 assets/forms/asset.py:97
#: assets/forms/asset.py:68 assets/forms/asset.py:103
msgid ""
"root or other NOPASSWD sudo privilege user existed in asset,If asset is "
"windows or other set any one, more see admin user left menu"
......@@ -677,16 +678,16 @@ msgstr ""
"root或其他拥有NOPASSWD: ALL权限的用户, 如果是windows或其它硬件可以随意设置一"
"个, 更多信息查看左侧 `管理用户` 菜单"
#: assets/forms/asset.py:65 assets/forms/asset.py:100
#: assets/forms/asset.py:71 assets/forms/asset.py:106
msgid "Windows 2016 RDP protocol is different, If is window 2016, set it"
msgstr "Windows 2016的RDP协议与之前不同,如果是请设置"
#: assets/forms/asset.py:66 assets/forms/asset.py:101
#: assets/forms/asset.py:72 assets/forms/asset.py:107
msgid ""
"If your have some network not connect with each other, you can set domain"
msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,使用网域网关跳转登录"
#: assets/forms/asset.py:108 assets/forms/asset.py:112
#: assets/forms/asset.py:114 assets/forms/asset.py:118
#: assets/forms/domain.py:17 assets/forms/label.py:15
#: perms/templates/perms/asset_permission_asset.html:88
#: xpack/plugins/change_auth_plan/forms.py:105
......@@ -715,11 +716,11 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC"
#: audits/templates/audits/login_log_list.html:51 authentication/forms.py:11
#: authentication/templates/authentication/login.html:64
#: authentication/templates/authentication/new_login.html:90
#: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:74
#: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:66
#: perms/templates/perms/asset_permission_user.html:55
#: perms/templates/perms/remote_app_permission_user.html:54
#: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:13
#: users/models/user.py:61 users/templates/users/_select_user_modal.html:14
#: users/models/user.py:62 users/templates/users/_select_user_modal.html:14
#: users/templates/users/user_detail.html:67
#: users/templates/users/user_list.html:36
#: users/templates/users/user_profile.html:47
......@@ -738,8 +739,7 @@ msgid "Password or private key passphrase"
msgstr "密码或密钥密码"
#: assets/forms/user.py:26 assets/models/base.py:29
#: assets/serializers/admin_user.py:19 assets/serializers/asset_user.py:34
#: assets/serializers/asset_user.py:87 assets/serializers/system_user.py:16
#: assets/serializers/asset_user.py:70
#: assets/templates/assets/_asset_user_auth_update_modal.html:21
#: assets/templates/assets/_asset_user_auth_view_modal.html:27
#: authentication/forms.py:13
......@@ -757,10 +757,9 @@ msgstr "密码或密钥密码"
msgid "Password"
msgstr "密码"
#: assets/forms/user.py:29 assets/serializers/asset_user.py:42
#: assets/serializers/asset_user.py:95
#: assets/forms/user.py:29 assets/serializers/asset_user.py:78
#: assets/templates/assets/_asset_user_auth_update_modal.html:27
#: users/models/user.py:90
#: users/models/user.py:91
msgid "Private key"
msgstr "ssh私钥"
......@@ -804,7 +803,7 @@ msgstr "如果选择手动登录模式,用户名和密码可以不填写"
msgid "Use comma split multi command, ex: /bin/whoami,/bin/ifconfig"
msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
#: assets/models/asset.py:71 assets/models/asset.py:96
#: assets/models/asset.py:65 assets/models/asset.py:90
#: assets/models/domain.py:50
#: assets/templates/assets/domain_gateway_list.html:69
#: assets/templates/assets/user_asset_list.html:168
......@@ -812,12 +811,12 @@ msgstr "使用逗号分隔多个命令,如: /bin/whoami,/sbin/ifconfig"
msgid "Port"
msgstr "端口"
#: assets/models/asset.py:91 assets/models/domain.py:49
#: assets/models/asset.py:85 assets/models/domain.py:49
#: assets/serializers/asset_user.py:29
#: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/_asset_user_list.html:15
#: assets/templates/assets/asset_detail.html:64
#: assets/templates/assets/asset_list.html:105
#: assets/templates/assets/asset_list.html:97
#: assets/templates/assets/domain_gateway_list.html:68
#: assets/templates/assets/user_asset_list.html:45
#: assets/templates/assets/user_asset_list.html:167
......@@ -829,24 +828,24 @@ msgstr "端口"
msgid "IP"
msgstr "IP"
#: assets/models/asset.py:92 assets/serializers/asset_user.py:28
#: assets/models/asset.py:86 assets/serializers/asset_user.py:28
#: assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/_asset_user_auth_update_modal.html:9
#: assets/templates/assets/_asset_user_auth_view_modal.html:15
#: assets/templates/assets/_asset_user_list.html:14
#: assets/templates/assets/asset_detail.html:60
#: assets/templates/assets/asset_list.html:104
#: assets/templates/assets/asset_list.html:96
#: assets/templates/assets/user_asset_list.html:44
#: assets/templates/assets/user_asset_list.html:166
#: perms/templates/perms/asset_permission_asset.html:54
#: perms/templates/perms/asset_permission_list.html:77 settings/forms.py:139
#: perms/templates/perms/asset_permission_list.html:69 settings/forms.py:139
#: users/templates/users/user_granted_asset.html:44
#: users/templates/users/user_group_granted_asset.html:44
#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:50
msgid "Hostname"
msgstr "主机名"
#: assets/models/asset.py:95 assets/models/asset.py:98
#: assets/models/asset.py:89 assets/models/asset.py:92
#: assets/models/domain.py:51 assets/models/user.py:110
#: assets/templates/assets/asset_detail.html:72
#: assets/templates/assets/domain_gateway_list.html:70
......@@ -857,85 +856,85 @@ msgstr "主机名"
msgid "Protocol"
msgstr "协议"
#: assets/models/asset.py:99 assets/templates/assets/asset_detail.html:108
#: assets/models/asset.py:93 assets/templates/assets/asset_detail.html:108
#: assets/templates/assets/user_asset_list.html:170
msgid "Platform"
msgstr "系统平台"
#: assets/models/asset.py:102 assets/models/cmd_filter.py:21
#: assets/models/asset.py:96 assets/models/cmd_filter.py:21
#: assets/models/domain.py:54 assets/models/label.py:22
#: assets/templates/assets/asset_detail.html:116
#: assets/templates/assets/user_asset_list.html:174
msgid "Is active"
msgstr "激活"
#: assets/models/asset.py:108 assets/templates/assets/asset_detail.html:68
#: assets/models/asset.py:102 assets/templates/assets/asset_detail.html:68
msgid "Public IP"
msgstr "公网IP"
#: assets/models/asset.py:109 assets/templates/assets/asset_detail.html:124
#: assets/models/asset.py:103 assets/templates/assets/asset_detail.html:124
msgid "Asset number"
msgstr "资产编号"
#: assets/models/asset.py:112 assets/templates/assets/asset_detail.html:88
#: assets/models/asset.py:106 assets/templates/assets/asset_detail.html:88
msgid "Vendor"
msgstr "制造商"
#: assets/models/asset.py:113 assets/templates/assets/asset_detail.html:92
#: assets/models/asset.py:107 assets/templates/assets/asset_detail.html:92
msgid "Model"
msgstr "型号"
#: assets/models/asset.py:114 assets/templates/assets/asset_detail.html:120
#: assets/models/asset.py:108 assets/templates/assets/asset_detail.html:120
msgid "Serial number"
msgstr "序列号"
#: assets/models/asset.py:116
#: assets/models/asset.py:110
msgid "CPU model"
msgstr "CPU型号"
#: assets/models/asset.py:117
#: assets/models/asset.py:111
#: xpack/plugins/license/templates/license/license_detail.html:80
msgid "CPU count"
msgstr "CPU数量"
#: assets/models/asset.py:118
#: assets/models/asset.py:112
msgid "CPU cores"
msgstr "CPU核数"
#: assets/models/asset.py:119
#: assets/models/asset.py:113
msgid "CPU vcpus"
msgstr "CPU总数"
#: assets/models/asset.py:120 assets/templates/assets/asset_detail.html:100
#: assets/models/asset.py:114 assets/templates/assets/asset_detail.html:100
msgid "Memory"
msgstr "内存"
#: assets/models/asset.py:121
#: assets/models/asset.py:115
msgid "Disk total"
msgstr "硬盘大小"
#: assets/models/asset.py:122
#: assets/models/asset.py:116
msgid "Disk info"
msgstr "硬盘信息"
#: assets/models/asset.py:124 assets/templates/assets/asset_detail.html:112
#: assets/models/asset.py:118 assets/templates/assets/asset_detail.html:112
#: assets/templates/assets/user_asset_list.html:171
msgid "OS"
msgstr "操作系统"
#: assets/models/asset.py:125
#: assets/models/asset.py:119
msgid "OS version"
msgstr "系统版本"
#: assets/models/asset.py:126
#: assets/models/asset.py:120
msgid "OS arch"
msgstr "系统架构"
#: assets/models/asset.py:127
#: assets/models/asset.py:121
msgid "Hostname raw"
msgstr "主机名原始"
#: assets/models/asset.py:129 assets/templates/assets/asset_create.html:46
#: assets/models/asset.py:123 assets/templates/assets/asset_create.html:46
#: assets/templates/assets/asset_detail.html:231 templates/_nav.html:26
msgid "Labels"
msgstr "标签管理"
......@@ -979,7 +978,7 @@ msgstr "带宽"
msgid "Contact"
msgstr "联系人"
#: assets/models/cluster.py:22 users/models/user.py:82
#: assets/models/cluster.py:22 users/models/user.py:83
#: users/templates/users/user_detail.html:76
msgid "Phone"
msgstr "手机"
......@@ -1001,12 +1000,12 @@ msgid "Operator"
msgstr "运营商"
#: assets/models/cluster.py:36 assets/models/group.py:34
#: perms/utils/asset_permission.py:64
#: perms/utils/asset_permission.py:67
msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14
#: users/models/user.py:485
#: users/models/user.py:443
msgid "System"
msgstr "系统"
......@@ -1113,11 +1112,11 @@ msgstr "默认资产组"
#: audits/templates/audits/password_change_log_list.html:50
#: ops/templates/ops/command_execution_list.html:35
#: ops/templates/ops/command_execution_list.html:60
#: perms/forms/asset_permission.py:40 perms/forms/remote_app_permission.py:31
#: perms/forms/asset_permission.py:41 perms/forms/remote_app_permission.py:31
#: perms/models/base.py:36
#: perms/templates/perms/asset_permission_create_update.html:41
#: perms/templates/perms/asset_permission_list.html:54
#: perms/templates/perms/asset_permission_list.html:119
#: perms/templates/perms/asset_permission_list.html:46
#: perms/templates/perms/asset_permission_list.html:111
#: perms/templates/perms/remote_app_permission_create_update.html:43
#: perms/templates/perms/remote_app_permission_list.html:15
#: templates/index.html:87 terminal/backends/command/models.py:12
......@@ -1125,7 +1124,7 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:301
#: users/models/user.py:37 users/models/user.py:473 users/serializers/v1.py:62
#: users/models/user.py:38 users/models/user.py:431 users/serializers/v1.py:88
#: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:36 users/views/user.py:407
#: xpack/plugins/orgs/forms.py:26
......@@ -1134,7 +1133,7 @@ msgstr "默认资产组"
msgid "User"
msgstr "用户"
#: assets/models/label.py:19 assets/models/node.py:21
#: assets/models/label.py:19 assets/models/node.py:240
#: assets/templates/assets/label_list.html:15 settings/models.py:30
msgid "Value"
msgstr "值"
......@@ -1143,11 +1142,11 @@ msgstr "值"
msgid "Category"
msgstr "分类"
#: assets/models/node.py:20
#: assets/models/node.py:239
msgid "Key"
msgstr "键"
#: assets/models/node.py:139
#: assets/models/node.py:296
msgid "New node"
msgstr "新节点"
......@@ -1221,7 +1220,7 @@ msgstr "协议组"
msgid "Hardware info"
msgstr "硬件信息"
#: assets/serializers/asset.py:74 orgs/mixins.py:220
#: assets/serializers/asset.py:74 orgs/mixins.py:192
msgid "Org name"
msgstr "组织名称"
......@@ -1229,9 +1228,16 @@ msgstr "组织名称"
msgid "Protocol duplicate: {}"
msgstr "协议重复: {}"
#: assets/serializers/asset_user.py:38 assets/serializers/asset_user.py:91
#: users/forms.py:248 users/models/user.py:93
#: users/templates/users/first_login.html:42
#: assets/serializers/asset_user.py:32
msgid "Backend"
msgstr "后端"
#: assets/serializers/asset_user.py:57
msgid "private key invalid"
msgstr "密钥不合法"
#: assets/serializers/asset_user.py:74 users/forms.py:248
#: users/models/user.py:94 users/templates/users/first_login.html:42
#: users/templates/users/user_password_update.html:46
#: users/templates/users/user_profile.html:68
#: users/templates/users/user_profile_update.html:43
......@@ -1239,13 +1245,9 @@ msgstr "协议重复: {}"
msgid "Public key"
msgstr "ssh公钥"
#: assets/serializers/asset_user.py:44
msgid "Backend"
msgstr "后端"
#: assets/serializers/asset_user.py:66
msgid "private key invalid"
msgstr "密钥不合法"
#: assets/serializers/node.py:33
msgid "The same level node name cannot be the same"
msgstr "同级别节点名字不能重复"
#: assets/serializers/system_user.py:31
msgid "Login mode display"
......@@ -1431,7 +1433,7 @@ msgid "Datetime"
msgstr "日期"
#: assets/templates/assets/_asset_user_list.html:36
#: assets/templates/assets/asset_list.html:166
#: assets/templates/assets/asset_list.html:138
msgid "Test datetime: "
msgstr "测试日期: "
......@@ -1466,6 +1468,34 @@ msgstr "SSH端口"
msgid "If use nat, set the ssh real port"
msgstr "如果使用了nat端口映射,请设置为ssh真实监听的端口"
#: assets/templates/assets/_node_tree.html:49
msgid "Add node"
msgstr "新建节点"
#: assets/templates/assets/_node_tree.html:50
msgid "Rename node"
msgstr "重命名节点"
#: assets/templates/assets/_node_tree.html:51
msgid "Delete node"
msgstr "删除节点"
#: assets/templates/assets/_node_tree.html:155
msgid "Create node failed"
msgstr "创建节点失败"
#: assets/templates/assets/_node_tree.html:167
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
#: assets/templates/assets/_node_tree.html:169
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
#: assets/templates/assets/_node_tree.html:243
msgid "Rename success"
msgstr "重命名成功"
#: assets/templates/assets/_system_user.html:37
#: assets/templates/assets/asset_create.html:16
#: assets/templates/assets/gateway_create_update.html:37
......@@ -1549,7 +1579,7 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:211
#: assets/templates/assets/asset_list.html:688
#: assets/templates/assets/asset_list.html:396
#: assets/templates/assets/cmd_filter_detail.html:106
#: assets/templates/assets/system_user_assets.html:100
#: assets/templates/assets/system_user_detail.html:182
......@@ -1564,7 +1594,6 @@ msgstr "选择节点"
#: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:119
#: users/templates/users/user_list.html:257
#: users/templates/users/user_profile.html:238
#: xpack/plugins/cloud/templates/cloud/account_create_update.html:34
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:36
#: xpack/plugins/interface/templates/interface/interface.html:103
......@@ -1590,7 +1619,7 @@ msgid "You can set any one for Windows or other hardware."
msgstr "Windows或其它硬件可以随意设置一个"
#: assets/templates/assets/admin_user_list.html:19
#: assets/templates/assets/asset_list.html:76
#: assets/templates/assets/asset_list.html:68
#: assets/templates/assets/system_user_list.html:23
#: audits/templates/audits/login_log_list.html:85
#: users/templates/users/user_group_list.html:10
......@@ -1600,7 +1629,7 @@ msgid "Export"
msgstr "导出"
#: assets/templates/assets/admin_user_list.html:24
#: assets/templates/assets/asset_list.html:81
#: assets/templates/assets/asset_list.html:73
#: assets/templates/assets/system_user_list.html:28
#: settings/templates/settings/_ldap_list_users_modal.html:100
#: users/templates/users/user_group_list.html:15
......@@ -1624,8 +1653,8 @@ msgstr "比例"
#: assets/templates/assets/admin_user_list.html:165
#: assets/templates/assets/admin_user_list.html:196
#: assets/templates/assets/asset_list.html:498
#: assets/templates/assets/asset_list.html:535
#: assets/templates/assets/asset_list.html:268
#: assets/templates/assets/asset_list.html:305
#: assets/templates/assets/system_user_list.html:224
#: assets/templates/assets/system_user_list.html:255
#: users/templates/users/user_group_list.html:163
......@@ -1681,7 +1710,7 @@ msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:154
#: assets/templates/assets/user_asset_list.html:46
#: perms/models/asset_permission.py:60 perms/models/base.py:38
#: perms/models/asset_permission.py:77 perms/models/base.py:38
#: perms/templates/perms/asset_permission_create_update.html:55
#: perms/templates/perms/asset_permission_detail.html:120
#: perms/templates/perms/remote_app_permission_create_update.html:54
......@@ -1712,99 +1741,63 @@ msgstr ""
"左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的,"
"右侧是属于该节点下的资产"
#: assets/templates/assets/asset_list.html:69 assets/views/asset.py:129
#: assets/templates/assets/asset_list.html:61 assets/views/asset.py:129
msgid "Create asset"
msgstr "创建资产"
#: assets/templates/assets/asset_list.html:106
#: assets/templates/assets/asset_list.html:98
msgid "Hardware"
msgstr "硬件"
#: assets/templates/assets/asset_list.html:117
#: assets/templates/assets/asset_list.html:109
#: users/templates/users/user_list.html:50
msgid "Delete selected"
msgstr "批量删除"
#: assets/templates/assets/asset_list.html:118
#: assets/templates/assets/asset_list.html:110
#: users/templates/users/user_list.html:51
msgid "Update selected"
msgstr "批量更新"
#: assets/templates/assets/asset_list.html:119
#: assets/templates/assets/asset_list.html:111
msgid "Remove from this node"
msgstr "从节点移除"
#: assets/templates/assets/asset_list.html:120
#: assets/templates/assets/asset_list.html:112
#: users/templates/users/user_list.html:52
msgid "Deactive selected"
msgstr "禁用所选"
#: assets/templates/assets/asset_list.html:121
#: assets/templates/assets/asset_list.html:113
#: users/templates/users/user_list.html:53
msgid "Active selected"
msgstr "激活所选"
#: assets/templates/assets/asset_list.html:138
msgid "Add node"
msgstr "新建节点"
#: assets/templates/assets/asset_list.html:139
msgid "Rename node"
msgstr "重命名节点"
#: assets/templates/assets/asset_list.html:140
msgid "Delete node"
msgstr "删除节点"
#: assets/templates/assets/asset_list.html:142
#: assets/templates/assets/asset_list.html:191
msgid "Add assets to node"
msgstr "添加资产到节点"
#: assets/templates/assets/asset_list.html:143
#: assets/templates/assets/asset_list.html:192
msgid "Move assets to node"
msgstr "移动资产到节点"
#: assets/templates/assets/asset_list.html:145
#: assets/templates/assets/asset_list.html:194
msgid "Refresh node hardware info"
msgstr "更新节点资产硬件信息"
#: assets/templates/assets/asset_list.html:146
#: assets/templates/assets/asset_list.html:195
msgid "Test node connective"
msgstr "测试节点资产可连接性"
#: assets/templates/assets/asset_list.html:148
msgid "Refresh all node assets amount"
msgstr "刷新所有节点资产数量"
#: assets/templates/assets/asset_list.html:150
#: assets/templates/assets/asset_list.html:197
msgid "Display only current node assets"
msgstr "仅显示当前节点资产"
#: assets/templates/assets/asset_list.html:151
#: assets/templates/assets/asset_list.html:198
msgid "Displays all child node assets"
msgstr "显示所有子节点资产"
#: assets/templates/assets/asset_list.html:235
msgid "Create node failed"
msgstr "创建节点失败"
#: assets/templates/assets/asset_list.html:247
msgid "Have child node, cancel"
msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:249
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
#: assets/templates/assets/asset_list.html:320
msgid "Rename success"
msgstr "重命名成功"
#: assets/templates/assets/asset_list.html:321
msgid "Rename failed, do not change the root node name"
msgstr "重命名失败,不能更改root节点的名称"
#: assets/templates/assets/asset_list.html:682
#: assets/templates/assets/asset_list.html:390
#: assets/templates/assets/system_user_list.html:165
#: users/templates/users/user_detail.html:382
#: users/templates/users/user_detail.html:408
......@@ -1815,11 +1808,11 @@ msgstr "重命名失败,不能更改root节点的名称"
msgid "Are you sure?"
msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:683
#: assets/templates/assets/asset_list.html:391
msgid "This will delete the selected assets !!!"
msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:686
#: assets/templates/assets/asset_list.html:394
#: assets/templates/assets/system_user_list.html:169
#: settings/templates/settings/terminal_setting.html:166
#: users/templates/users/user_detail.html:386
......@@ -1833,16 +1826,16 @@ msgstr "删除选择资产"
msgid "Cancel"
msgstr "取消"
#: assets/templates/assets/asset_list.html:699
#: assets/templates/assets/asset_list.html:407
msgid "Asset Deleted."
msgstr "已被删除"
#: assets/templates/assets/asset_list.html:700
#: assets/templates/assets/asset_list.html:704
#: assets/templates/assets/asset_list.html:408
#: assets/templates/assets/asset_list.html:412
msgid "Asset Delete"
msgstr "删除"
#: assets/templates/assets/asset_list.html:703
#: assets/templates/assets/asset_list.html:411
msgid "Asset Deleting failed."
msgstr "删除失败"
......@@ -2232,7 +2225,7 @@ msgstr "Agent"
#: audits/models.py:99 audits/templates/audits/login_log_list.html:56
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
#: users/forms.py:160 users/models/user.py:85
#: users/forms.py:160 users/models/user.py:86
#: users/templates/users/first_login.html:45
msgid "MFA"
msgstr "MFA"
......@@ -2652,7 +2645,7 @@ msgstr "不能包含特殊字符"
msgid "This field must be unique."
msgstr "字段必须唯一"
#: jumpserver/views.py:188
#: jumpserver/views.py:190
msgid ""
"<div>Luna is a separately deployed program, you need to deploy Luna, coco, "
"configure nginx for url distribution,</div> </div>If you see this page, "
......@@ -3003,59 +2996,63 @@ msgstr "命令执行列表"
msgid "Command execution"
msgstr "命令执行"
#: orgs/mixins.py:82 orgs/mixins.py:219 orgs/models.py:24
#: orgs/mixins.py:71 orgs/mixins.py:191 orgs/models.py:26
msgid "Organization"
msgstr "组织"
#: perms/const.py:18 settings/forms.py:143
#: perms/const.py:18 perms/models/asset_permission.py:44 settings/forms.py:143
msgid "All"
msgstr "全部"
#: perms/const.py:20
#: perms/const.py:20 perms/models/asset_permission.py:46
msgid "Upload file"
msgstr "上传文件"
#: perms/const.py:21
#: perms/const.py:21 perms/models/asset_permission.py:48
msgid "Download file"
msgstr "下载文件"
#: perms/forms/asset_permission.py:43 perms/forms/remote_app_permission.py:34
#: perms/models/asset_permission.py:58 perms/models/base.py:37
#: perms/templates/perms/asset_permission_list.html:55
#: perms/templates/perms/asset_permission_list.html:75
#: perms/templates/perms/asset_permission_list.html:122
#: perms/forms/asset_permission.py:44 perms/forms/remote_app_permission.py:34
#: perms/models/asset_permission.py:75 perms/models/base.py:37
#: perms/templates/perms/asset_permission_list.html:47
#: perms/templates/perms/asset_permission_list.html:67
#: perms/templates/perms/asset_permission_list.html:114
#: perms/templates/perms/remote_app_permission_list.html:16
#: templates/_nav.html:14 users/forms.py:271 users/models/group.py:26
#: users/models/user.py:69 users/templates/users/_select_user_modal.html:16
#: users/models/user.py:70 users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:213
#: users/templates/users/user_list.html:38
#: xpack/plugins/orgs/templates/orgs/org_list.html:15
msgid "User group"
msgstr "用户组"
#: perms/forms/asset_permission.py:62
#: perms/forms/asset_permission.py:63
msgid ""
"Tips: The RDP protocol does not support separate controls for uploading or "
"downloading files"
msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
#: perms/forms/asset_permission.py:72 perms/forms/remote_app_permission.py:47
#: perms/forms/asset_permission.py:73 perms/forms/remote_app_permission.py:47
msgid "User or group at least one required"
msgstr "用户和用户组至少选一个"
#: perms/forms/asset_permission.py:81
#: perms/forms/asset_permission.py:82
msgid "Asset or group at least one required"
msgstr "资产和节点至少选一个"
#: perms/models/asset_permission.py:44 perms/models/asset_permission.py:70
#: perms/models/asset_permission.py:47
msgid "Upload download"
msgstr "上传下载"
#: perms/models/asset_permission.py:61 perms/models/asset_permission.py:87
#: templates/_nav.html:44
msgid "Asset permission"
msgstr "资产授权"
#: perms/models/asset_permission.py:61 perms/models/base.py:40
#: perms/models/asset_permission.py:78 perms/models/base.py:40
#: perms/templates/perms/asset_permission_detail.html:90
#: perms/templates/perms/remote_app_permission_detail.html:82
#: users/models/user.py:101 users/templates/users/user_detail.html:107
#: users/models/user.py:102 users/templates/users/user_detail.html:107
#: users/templates/users/user_profile.html:116
msgid "Date expired"
msgstr "失效日期"
......@@ -3145,13 +3142,13 @@ msgstr "系统用户数量"
msgid "Select system users"
msgstr "选择系统用户"
#: perms/templates/perms/asset_permission_list.html:46
#: perms/templates/perms/asset_permission_list.html:38
#: perms/templates/perms/remote_app_permission_list.html:6
msgid "Create permission"
msgstr "创建授权规则"
#: perms/templates/perms/asset_permission_list.html:59
#: perms/templates/perms/asset_permission_list.html:73
#: perms/templates/perms/asset_permission_list.html:51
#: perms/templates/perms/asset_permission_list.html:65
#: perms/templates/perms/remote_app_permission_list.html:18
#: users/templates/users/user_list.html:40 xpack/plugins/cloud/models.py:53
#: xpack/plugins/cloud/templates/cloud/account_detail.html:58
......@@ -3201,9 +3198,9 @@ msgstr "添加用户"
msgid "Add user group to this permission"
msgstr "添加用户组"
#: perms/views/asset_permission.py:34 perms/views/asset_permission.py:67
#: perms/views/asset_permission.py:83 perms/views/asset_permission.py:99
#: perms/views/asset_permission.py:136 perms/views/asset_permission.py:169
#: perms/views/asset_permission.py:34 perms/views/asset_permission.py:65
#: perms/views/asset_permission.py:81 perms/views/asset_permission.py:97
#: perms/views/asset_permission.py:134 perms/views/asset_permission.py:167
#: perms/views/remote_app_permission.py:33
#: perms/views/remote_app_permission.py:49
#: perms/views/remote_app_permission.py:65
......@@ -3218,23 +3215,23 @@ msgstr "权限管理"
msgid "Asset permission list"
msgstr "资产授权列表"
#: perms/views/asset_permission.py:68
#: perms/views/asset_permission.py:66
msgid "Create asset permission"
msgstr "创建权限规则"
#: perms/views/asset_permission.py:84
#: perms/views/asset_permission.py:82
msgid "Update asset permission"
msgstr "更新资产授权"
#: perms/views/asset_permission.py:100
#: perms/views/asset_permission.py:98
msgid "Asset permission detail"
msgstr "资产授权详情"
#: perms/views/asset_permission.py:137
#: perms/views/asset_permission.py:135
msgid "Asset permission user list"
msgstr "资产授权用户列表"
#: perms/views/asset_permission.py:170
#: perms/views/asset_permission.py:168
msgid "Asset permission asset list"
msgstr "资产授权资产列表"
......@@ -3591,7 +3588,7 @@ msgid "Please submit the LDAP configuration before import"
msgstr "请先提交LDAP配置再进行导入"
#: settings/templates/settings/_ldap_list_users_modal.html:39
#: users/models/user.py:65 users/templates/users/user_detail.html:71
#: users/models/user.py:66 users/templates/users/user_detail.html:71
#: users/templates/users/user_profile.html:59
msgid "Email"
msgstr "邮件"
......@@ -4372,15 +4369,15 @@ msgid ""
"You should use your ssh client tools connect terminal: {} <br /> <br />{}"
msgstr "你可以使用ssh客户端工具连接终端"
#: users/api/user.py:78 users/api/user.py:89 users/api/user.py:115
#: users/api/user.py:79 users/api/user.py:90 users/api/user.py:116
msgid "You do not have permission."
msgstr "你没有权限"
#: users/api/user.py:219
#: users/api/user.py:221
msgid "Could not reset self otp, use profile reset instead"
msgstr "不能再该页面重置MFA, 请去个人信息页面重置"
#: users/forms.py:32 users/models/user.py:73
#: users/forms.py:32 users/models/user.py:74
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:37
......@@ -4408,7 +4405,7 @@ msgstr "添加到用户组"
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
#: users/forms.py:90 users/forms.py:237 users/serializers/v1.py:48
#: users/forms.py:90 users/forms.py:237 users/serializers/v1.py:74
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
......@@ -4489,88 +4486,94 @@ msgstr "复制你的公钥到这里"
msgid "Select users"
msgstr "选择用户"
#: users/models/user.py:36 users/models/user.py:481
#: users/models/user.py:37 users/models/user.py:439
msgid "Administrator"
msgstr "管理员"
#: users/models/user.py:38
#: users/models/user.py:39
msgid "Application"
msgstr "应用程序"
#: users/models/user.py:39
#: users/models/user.py:40
msgid "Auditor"
msgstr "审计员"
#: users/models/user.py:42 users/templates/users/user_profile.html:92
#: users/models/user.py:43 users/templates/users/user_profile.html:92
#: users/templates/users/user_profile.html:159
#: users/templates/users/user_profile.html:162
msgid "Disable"
msgstr "禁用"
#: users/models/user.py:43 users/templates/users/user_profile.html:90
#: users/models/user.py:44 users/templates/users/user_profile.html:90
#: users/templates/users/user_profile.html:166
msgid "Enable"
msgstr "启用"
#: users/models/user.py:44 users/templates/users/user_profile.html:88
#: users/models/user.py:45 users/templates/users/user_profile.html:88
msgid "Force enable"
msgstr "强制启用"
#: users/models/user.py:76
#: users/models/user.py:77
msgid "Avatar"
msgstr "头像"
#: users/models/user.py:79 users/templates/users/user_detail.html:82
#: users/models/user.py:80 users/templates/users/user_detail.html:82
msgid "Wechat"
msgstr "微信"
#: users/models/user.py:108 users/templates/users/user_detail.html:103
#: users/models/user.py:109 users/templates/users/user_detail.html:103
#: users/templates/users/user_list.html:39
#: users/templates/users/user_profile.html:100
msgid "Source"
msgstr "用户来源"
#: users/models/user.py:112
#: users/models/user.py:113
msgid "Date password last updated"
msgstr "最后更新密码日期"
#: users/models/user.py:138 users/templates/users/user_update.html:22
#: users/models/user.py:139 users/templates/users/user_update.html:22
#: users/views/login.py:46 users/views/login.py:107 users/views/user.py:439
msgid "User auth from {}, go there change password"
msgstr "用户认证源来自 {}, 请去相应系统修改密码"
#: users/models/user.py:484
#: users/models/user.py:442
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
#: users/serializers/v1.py:29
#: users/serializers/v1.py:32
msgid "Groups name"
msgstr "用户组名"
#: users/serializers/v1.py:30
#: users/serializers/v1.py:33
msgid "Source name"
msgstr "用户来源名"
#: users/serializers/v1.py:31
#: users/serializers/v1.py:34
msgid "Is first login"
msgstr "首次登录"
#: users/serializers/v1.py:32
#: users/serializers/v1.py:35
msgid "Role name"
msgstr "角色名"
#: users/serializers/v1.py:33
#: users/serializers/v1.py:36
msgid "Is valid"
msgstr "账户是否有效"
#: users/serializers/v1.py:34
#: users/serializers/v1.py:37
msgid "Is expired"
msgstr " 是否过期"
#: users/serializers/v1.py:35
#: users/serializers/v1.py:38
msgid "Avatar url"
msgstr "头像路径"
#: users/serializers/v1.py:46
#, fuzzy
#| msgid "Password does not match"
msgid "Password does not match security rules"
msgstr "密码不一致"
#: users/serializers_v2/user.py:36
msgid "name not unique"
msgstr "名称重复"
......@@ -4846,14 +4849,11 @@ msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
#: users/templates/users/user_detail.html:427
#: users/templates/users/user_profile.html:227
msgid "Successfully updated the SSH public key."
msgstr "更新ssh密钥成功"
#: users/templates/users/user_detail.html:428
#: users/templates/users/user_detail.html:432
#: users/templates/users/user_profile.html:228
#: users/templates/users/user_profile.html:233
msgid "User SSH public key update"
msgstr "ssh密钥"
......@@ -4992,10 +4992,6 @@ msgstr "更改SSH密钥"
msgid "Reset public key and download"
msgstr "重置并下载SSH密钥"
#: users/templates/users/user_profile.html:231
msgid "Failed to update SSH public key."
msgstr "更新密钥失败"
#: users/templates/users/user_pubkey_update.html:51
msgid "Old public key"
msgstr "原来ssh密钥"
......@@ -5950,6 +5946,15 @@ msgstr "密码匣子"
msgid "vault create"
msgstr "创建"
#~ msgid "Refresh all node assets amount"
#~ msgstr "刷新所有节点资产数量"
#~ msgid "Rename failed, do not change the root node name"
#~ msgstr "重命名失败,不能更改root节点的名称"
#~ msgid "Failed to update SSH public key."
#~ msgstr "更新密钥失败"
#~ msgid "Unreachable assets"
#~ msgstr "不可达资产"
......
# -*- coding: utf-8 -*-
#
from assets.models import Node
from orgs.utils import set_current_org, current_org
from orgs.utils import set_current_org, current_org, get_current_org
......@@ -4,7 +4,8 @@ import traceback
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import redirect, get_object_or_404
from django.forms import ModelForm
from django import forms
from django.core.exceptions import ValidationError
from django.http.response import HttpResponseForbidden
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator
......@@ -101,6 +102,26 @@ class OrgModelMixin(models.Model):
else:
return name
def validate_unique(self, exclude=None):
"""
Check unique constraints on the model and raise ValidationError if any
failed.
Form 提交时会使用这个检验
"""
self.org_id = current_org.id if current_org.is_real() else ''
if exclude and 'org_id' in exclude:
exclude.remove('org_id')
unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
errors = self._perform_unique_checks(unique_checks)
date_errors = self._perform_date_checks(date_checks)
for k, v in date_errors.items():
errors.setdefault(k, []).extend(v)
if errors:
raise ValidationError(errors)
class Meta:
abstract = True
......@@ -123,11 +144,9 @@ class RootOrgViewMixin:
return super().dispatch(request, *args, **kwargs)
class OrgModelForm(ModelForm):
class OrgModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# if 'initial' not in kwargs:
# return
for name, field in self.fields.items():
if not hasattr(field, 'queryset'):
continue
......
......@@ -6,7 +6,7 @@ from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Organization
from .hands import set_current_org, current_org, Node
from .hands import set_current_org, current_org, Node, get_current_org
from perms.models import AssetPermission
from users.models import UserGroup
......@@ -14,7 +14,7 @@ from users.models import UserGroup
@receiver(post_save, sender=Organization)
def on_org_create_or_update(sender, instance=None, created=False, **kwargs):
if instance:
old_org = current_org
old_org = get_current_org()
set_current_org(instance)
node_root = Node.root()
if node_root.value != instance.name:
......
......@@ -20,16 +20,10 @@ from .. import serializers
__all__ = [
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
'AssetPermissionAddAssetApi', 'ActionViewSet',
'AssetPermissionAddAssetApi',
]
class ActionViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Action.objects.all()
serializer_class = serializers.ActionSerializer
permission_classes = (IsOrgAdmin,)
class AssetPermissionViewSet(viewsets.ModelViewSet):
"""
资产授权列表的增删改查api
......
......@@ -14,7 +14,6 @@ from rest_framework.pagination import LimitOffsetPagination
from common.permissions import IsValidUser, IsOrgAdminOrAppUser
from common.tree import TreeNodeSerializer
from common.utils import get_logger
from orgs.utils import set_to_root_org
from ..utils import (
AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node,
check_system_user_action, RemoteAppPermissionUtil,
......@@ -515,6 +514,7 @@ class ValidateUserRemoteAppPermissionApi(APIView):
permission_classes = (IsOrgAdminOrAppUser,)
def get(self, request, *args, **kwargs):
self.change_org_if_need(request, kwargs)
user_id = request.query_params.get('user_id', '')
remote_app_id = request.query_params.get('remote_app_id', '')
user = get_object_or_404(User, id=user_id)
......
# ~*~ coding: utf-8 ~*~
from __future__ import absolute_import, unicode_literals
from functools import reduce
from django import forms
from django.utils.translation import ugettext_lazy as _
......@@ -18,17 +19,22 @@ class AssetPermissionForm(OrgModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
users_field = self.fields.get('users')
if hasattr(users_field, 'queryset'):
users_field.queryset = current_org.get_org_users()
assets_field = self.fields.get('assets')
users_field.queryset = current_org.get_org_users()
# 前端渲染优化, 防止过多资产
if not self.data:
instance = kwargs.get('instance')
assets_field = self.fields['assets']
if instance:
assets_field.queryset = instance.assets.all()
else:
assets_field.queryset = Asset.objects.none()
nodes_field = self.fields['nodes']
nodes_field._queryset = Node.get_queryset()
def clean_action(self):
actions = self.cleaned_data.get("action")
return reduce(lambda x, y: x | y, actions)
class Meta:
model = AssetPermission
......@@ -51,16 +57,14 @@ class AssetPermissionForm(OrgModelForm):
'system_users': forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('System user')}
),
'actions': forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('Action')}
)
'action': forms.CheckboxSelectMultiple()
}
labels = {
'nodes': _("Node"),
}
help_texts = {
'actions': _('Tips: The RDP protocol does not support separate '
'controls for uploading or downloading files')
'action': _('Tips: The RDP protocol does not support separate '
'controls for uploading or downloading files')
}
def clean_user_groups(self):
......
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-25 10:15
from __future__ import unicode_literals
import common.utils
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('users', '0004_auto_20180125_1218'),
('assets', '0007_auto_20180225_1815'),
('perms', '0002_auto_20171228_0025'),
]
operations = [
migrations.CreateModel(
name='NodePermission',
fields=[
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('is_active', models.BooleanField(default=True, verbose_name='Active')),
('date_expired', models.DateTimeField(default=common.utils.date_expired_default, verbose_name='Date expired')),
('created_by', models.CharField(blank=True, max_length=128, verbose_name='Created by')),
('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')),
('comment', models.TextField(blank=True, verbose_name='Comment')),
('node', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.Node', verbose_name='Node')),
('system_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.SystemUser', verbose_name='System user')),
('user_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.UserGroup', verbose_name='User group')),
],
options={
'verbose_name': 'Asset permission',
},
),
migrations.AlterUniqueTogether(
name='nodepermission',
unique_together=set([('node', 'user_group', 'system_user')]),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-11 03:35
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('assets', '0013_auto_20180411_1135'),
('perms', '0003_auto_20180225_1815'),
]
operations = [
migrations.RemoveField(
model_name='assetpermission',
name='asset_groups',
),
migrations.AddField(
model_name='assetpermission',
name='date_start',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Date start'),
),
migrations.AddField(
model_name='assetpermission',
name='nodes',
field=models.ManyToManyField(blank=True, related_name='granted_by_permissions', to='assets.Node', verbose_name='Nodes'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-11 03:35
from __future__ import unicode_literals
from django.db import migrations, models
import django.utils.timezone
def migrate_node_permissions(apps, schema_editor):
node_perm_model = apps.get_model("perms", "NodePermission")
asset_perm_model = apps.get_model("perms", "AssetPermission")
db_alias = schema_editor.connection.alias
for old in node_perm_model.objects.using(db_alias).all():
perm = asset_perm_model.objects.using(db_alias).create(
name="{}-{}-{}".format(
old.node.value,
old.user_group.name,
old.system_user.name
),
is_active=old.is_active,
date_expired=old.date_expired,
created_by=old.date_expired,
date_created=old.date_created,
comment=old.comment,
)
perm.user_groups.add(old.user_group)
perm.nodes.add(old.node)
perm.system_users.add(old.system_user)
def migrate_system_assets_relation(apps, schema_editor):
system_user_model = apps.get_model("assets", "SystemUser")
db_alias = schema_editor.connection.alias
for s in system_user_model.objects.using(db_alias).all():
nodes = list(s.nodes.all())
s.nodes.set([])
s.nodes.set(nodes)
class Migration(migrations.Migration):
dependencies = [
('perms', '0004_auto_20180411_1135'),
]
operations = [
migrations.RunPython(migrate_node_permissions),
migrations.RunPython(migrate_system_assets_relation),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-06-06 07:05
from __future__ import unicode_literals
import common.utils
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('perms', '0005_migrate_data_20180411_1144'),
]
operations = [
migrations.AlterField(
model_name='assetpermission',
name='date_expired',
field=models.DateTimeField(db_index=True, default=common.utils.date_expired_default, verbose_name='Date expired'),
),
migrations.AlterField(
model_name='assetpermission',
name='date_start',
field=models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='Date start'),
),
]
# Generated by Django 2.1.7 on 2019-06-28 11:47
from django.db import migrations, models
from functools import reduce
def migrate_old_actions(apps, schema_editor):
from orgs.utils import set_to_root_org
from ..models import ActionFlag
set_to_root_org()
perm_model = apps.get_model('perms', 'AssetPermission')
db_alias = schema_editor.connection.alias
perms = perm_model.objects.using(db_alias).all()
actions_map = {
"all": ActionFlag.ALL,
"connect": ActionFlag.CONNECT,
"upload_file": ActionFlag.UPLOAD,
"download_file": ActionFlag.DOWNLOAD,
}
for perm in perms:
actions = perm.actions.all()
new_actions = [actions_map.get(action.name, ActionFlag.ALL) for action in actions]
new_action = reduce(lambda x, y: x | y, new_actions)
perm.action = new_action
perm.save()
class Migration(migrations.Migration):
dependencies = [
('perms', '0005_auto_20190521_1619'),
]
operations = [
migrations.AddField(
model_name='assetpermission',
name='action',
field=models.IntegerField(
choices=[(255, 'All'), (1, 'Connect'), (2, 'Upload file'),
(6, 'Upload download'), (4, 'Download file')],
default=255, verbose_name='Action'),
),
migrations.RunPython(migrate_old_actions),
]
# Generated by Django 2.0.7 on 2018-08-07 03:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('perms', '0006_auto_20180606_1505'),
]
operations = [
migrations.AddField(
model_name='assetpermission',
name='org_id',
field=models.CharField(blank=True, default=None, max_length=36, null=True),
),
migrations.AddField(
model_name='nodepermission',
name='org_id',
field=models.CharField(blank=True, default=None, max_length=36, null=True),
),
migrations.AlterField(
model_name='assetpermission',
name='name',
field=models.CharField(max_length=128, verbose_name='Name'),
),
migrations.AlterUniqueTogether(
name='assetpermission',
unique_together={('org_id', 'name')},
),
migrations.AlterUniqueTogether(
name='nodepermission',
unique_together=set(),
),
]
# Generated by Django 2.1 on 2018-09-03 03:32
# Generated by Django 2.1.7 on 2019-06-28 12:02
from django.db import migrations
......@@ -6,12 +6,12 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('perms', '0008_auto_20180816_1652'),
('perms', '0006_auto_20190628_1921'),
]
operations = [
migrations.AlterModelOptions(
name='assetpermission',
options={'verbose_name': 'Asset permission'},
migrations.RemoveField(
model_name='assetpermission',
name='actions',
),
]
# Generated by Django 2.0.7 on 2018-08-16 08:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('perms', '0007_auto_20180807_1116'),
]
operations = [
migrations.AlterField(
model_name='assetpermission',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
migrations.AlterField(
model_name='nodepermission',
name='org_id',
field=models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization'),
),
]
......@@ -11,7 +11,7 @@ from .base import BasePermission
__all__ = [
'Action', 'AssetPermission', 'NodePermission',
'Action', 'AssetPermission', 'NodePermission', 'ActionFlag'
]
......@@ -33,11 +33,28 @@ class Action(models.Model):
return cls.objects.get(name=PERMS_ACTION_NAME_ALL)
class ActionFlag:
CONNECT = 0b00000001
UPLOAD = 0b00000010
DOWNLOAD = 0b00000100
UPDOWNLOAD = CONNECT | DOWNLOAD
ALL = 0b11111111
CHOICES = (
(ALL, _('All')),
(CONNECT, _('Connect')),
(UPLOAD, _('Upload file')),
(UPDOWNLOAD, _("Upload download")),
(DOWNLOAD, _('Download file')),
)
class AssetPermission(BasePermission):
assets = models.ManyToManyField('assets.Asset', related_name='granted_by_permissions', blank=True, verbose_name=_("Asset"))
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes"))
system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user"))
actions = models.ManyToManyField('Action', related_name='permissions', blank=True, verbose_name=_('Action'))
# actions = models.ManyToManyField(Action, related_name='permissions', blank=True, verbose_name=_('Action'))
action = models.IntegerField(choices=ActionFlag.CHOICES, default=ActionFlag.ALL, verbose_name=_("Action"))
class Meta:
unique_together = [('org_id', 'name')]
......
......@@ -13,16 +13,10 @@ __all__ = [
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
'AssetPermissionNodeSerializer', 'GrantedNodeSerializer',
'ActionSerializer', 'NodeGrantedSerializer',
'NodeGrantedSerializer',
]
class ActionSerializer(serializers.ModelSerializer):
class Meta:
model = Action
fields = '__all__'
class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer):
class Meta:
model = AssetPermission
......@@ -35,7 +29,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer):
assets = StringManyToManyField(many=True, read_only=True)
nodes = StringManyToManyField(many=True, read_only=True)
system_users = StringManyToManyField(many=True, read_only=True)
actions = StringManyToManyField(many=True, read_only=True)
action = serializers.IntegerField(read_only=True)
is_valid = serializers.BooleanField()
is_expired = serializers.BooleanField()
......
......@@ -25,13 +25,6 @@ def on_transaction_commit(func):
@on_transaction_commit
def on_permission_created(sender, instance=None, created=False, **kwargs):
AssetPermissionUtil.expire_all_cache()
actions = instance.actions.all()
if created and not actions:
default_action = Action.get_action_all()
instance.actions.add(default_action)
logger.debug(
"Set default action to perms: {}".format(default_action, instance)
)
@receiver(post_save, sender=AssetPermission)
......
......@@ -48,7 +48,7 @@
{% bootstrap_field form.system_users layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Action' %}</h3>
{% bootstrap_field form.actions layout="horizontal" %}
{% bootstrap_field form.action layout="horizontal" %}
<div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3>
<div class="form-group">
......@@ -143,6 +143,34 @@ $(document).ready(function () {
$('#id_assets').val(assets).trigger('change');
$("#asset_list_modal").modal('hide');
});
})
.on("submit", "form", function (evt) {
evt.preventDefault();
var the_url = '{% url 'api-perms:asset-permission-list' %}';
var redirect_to = '{% url "perms:asset-permission-list" %}';
var method = "POST";
var form = $("form");
var data = form.serializeObject();
console.log(data)
var actions = data.action;
var action = 0;
for (i=0;i<actions.length;i++) {
console.log(actions[i])
action |= actions[i];
}
data.action = action;
objectAttrsIsList(data, ['users', 'user_groups', 'system_users', 'nodes', 'assets']);
objectAttrsIsDatetime(data, ['date_start', 'date_expired']);
objectAttrsIsBool(data, ['is_active'])
console.log(data)
var props = {
url: the_url,
data: data,
method: method,
form: form,
redirect_to: redirect_to
};
formSubmit(props);
})
</script>
{% endblock %}
\ No newline at end of file
......@@ -24,15 +24,7 @@
<div class="wrapper wrapper-content">
<div class="row">
<div class="col-lg-3" id="split-left" style="padding-left: 3px">
<div class="ibox float-e-margins">
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
<div class="file-manager ">
<div id="assetTree" class="ztree">
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
{% include 'assets/_node_tree.html' %}
</div>
<div class="col-lg-9 animated fadeInRight" id="split-right">
<div class="tree-toggle">
......@@ -86,7 +78,7 @@
<script>
var zTree, table, show = 0;
function onSelected(event, treeNode) {
function onNodeSelected(event, treeNode) {
setCookie('node_selected', treeNode.id);
var url = table.ajax.url();
if (treeNode.meta.type === 'node') {
......@@ -102,7 +94,7 @@ function onSelected(event, treeNode) {
}
function beforeAsync(treeId, treeNode) {
function beforeNodeAsync(treeId, treeNode) {
if (treeNode) {
return treeNode.meta.type === 'node'
}
......@@ -204,28 +196,12 @@ function initTable() {
function initTree() {
var setting = {
view: {
dblClickExpand: false,
showLine: true
},
data: {
simpleData: {
enable: true
}
},
async: {
enable: true,
url: "{% url 'api-assets:node-children-tree' %}?assets=1",
autoParam:["id=key", "name=n", "level=lv"],
type: 'get'
},
callback: {
onSelected: onSelected,
beforeAsync: beforeAsync
}
};
zTree = $.fn.zTree.init($("#assetTree"), setting);
initNodeTree({
onSelected: onNodeSelected,
beforeAsync: beforeNodeAsync,
showMenu: false,
showAssets: true,
})
}
function toggle() {
......
......@@ -7,7 +7,6 @@ from .. import api
app_name = 'perms'
router = routers.DefaultRouter()
router.register('actions', api.ActionViewSet, 'action')
router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission')
router.register('remote-app-permissions', api.RemoteAppPermissionViewSet, 'remote-app-permission')
......
......@@ -5,6 +5,7 @@ from collections import defaultdict
import json
from hashlib import md5
import time
import itertools
from django.utils import timezone
from django.db.models import Q
......@@ -102,11 +103,11 @@ def get_user_permissions(user, include_group=True):
arg = Q(users=user) | Q(user_groups__in=groups)
else:
arg = Q(users=user)
return AssetPermission.objects.all().valid().filter(arg)
return AssetPermission.objects.valid().filter(arg)
def get_user_group_permissions(user_group):
return AssetPermission.objects.all().valid().filter(
return AssetPermission.objects.valid().filter(
user_groups=user_group
)
......@@ -117,15 +118,15 @@ def get_asset_permissions(asset, include_node=True):
arg = Q(assets=asset) | Q(nodes__in=nodes)
else:
arg = Q(assets=asset)
return AssetPermission.objects.all().valid().filter(arg)
return AssetPermission.objects.valid().filter(arg)
def get_node_permissions(node):
return AssetPermission.objects.all().valid().filter(nodes=node)
return AssetPermission.objects.valid().filter(nodes=node)
def get_system_user_permissions(system_user):
return AssetPermission.objects.valid().all().filter(
return AssetPermission.objects.valid().filter(
system_users=system_user
)
......@@ -141,11 +142,6 @@ def timeit(func):
return wrapper
class AssetGranted:
def __init__(self):
self.system_users = {}
class AssetPermissionCacheMixin:
CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_'
CACHE_META_KEY_PREFIX = '_ASSET_PERM_META_KEY_'
......@@ -286,6 +282,38 @@ class AssetPermissionCacheMixin:
cache.delete_pattern(key)
class FlatPermissionQueryset:
def __init__(self):
self.queryset = defaultdict(list)
def add(self, permission):
self.queryset[permission.id].append(permission)
def add_many(self, assets_or_nodes, system_users, actions):
if any([assets_or_nodes, system_users, actions]):
return
iterable = itertools.product(assets_or_nodes, system_users, actions)
for source, sysuser, action in iterable:
permission = FlatPermission(source, sysuser, action)
self.add(permission)
def clean(self):
pass
class FlatPermission:
def __init__(self, asset_or_node, system_user, action):
self.id = asset_or_node.id
self.source = asset_or_node
self.system_user = system_user
self.action = action
def __eq__(self, other):
pass
class AssetPermissionUtil(AssetPermissionCacheMixin):
get_permissions_map = {
"User": get_user_permissions,
......@@ -344,19 +372,15 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
def get_nodes_direct(self):
"""
返回用户/组授权规则直接关联的节点
:return: {asset1: {system_user1: {'actions': set()},}}
:return: {node1: {system_user1: {'actions': set()},}}
"""
nodes = defaultdict(dict)
permissions = self.permissions.prefetch_related('nodes', 'system_users', 'actions')
nodes = FlatPermissionQueryset()
permissions = self.permissions
for perm in permissions:
actions = perm.actions.all()
for node in perm.nodes.all():
system_users = perm.system_users.all()
system_users = self._structured_system_user(system_users, actions)
nodes[node].update(system_users)
self.tree.add_nodes(nodes.keys())
# 替换成优化过的node
nodes = {self.tree.node_util.get_node_by_key(k.key): v for k, v in nodes.items()}
system_users = perm.system_users.all()
_nodes = perm.nodes.all()
nodes.add_many(_nodes, system_users, actions)
return nodes
@timeit
......@@ -385,24 +409,18 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
assets = self.get_assets_direct()
nodes = self.get_nodes_direct()
# for node, system_users in nodes.items():
# print(9999, node)
# _assets = node.get_all_valid_assets()
# print(".......... end .......")
# print(">>>>> Node<<<<<<<<<<<<: ", node.value)
# _assets = list(node.get_all_valid_assets())
# for asset in _assets:
# print(">>asset")
# for system_user, attr_dict in system_users.items():
# print(">>>system user")
# if not asset.has_protocol(system_user.protocol):
# continue
# if system_user in assets[asset]:
# actions = assets[asset][system_user]['actions']
# attr_dict['actions'].update(actions)
# system_users.update({system_user: attr_dict})
# print("<<<system user")
# print("<<<asset")
# assets[asset].update(system_users)
# print(">>>>>>")
#
__assets = defaultdict(set)
for asset, system_users in assets.items():
for system_user, attr_dict in system_users.items():
......@@ -507,8 +525,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
'id': asset.id,
'hostname': asset.hostname,
'ip': asset.ip,
'protocols': [{"name": p.name, "port": p.port}
for p in asset.protocols.all()],
'protocols': [str(p) for p in asset.protocols.all()],
'platform': asset.platform,
'domain': None if not asset.domain else asset.domain.id,
'is_active': asset.is_active,
......
......@@ -58,8 +58,6 @@ class AssetPermissionCreateView(PermissionsMixin, CreateView):
assets_id = assets_id.split(",")
assets = Asset.objects.filter(id__in=assets_id)
form['assets'].initial = assets
form['actions'].initial = Action.objects.get(name=PERMS_ACTION_NAME_ALL)
return form
def get_context_data(self, **kwargs):
......
......@@ -277,7 +277,7 @@ function APIUpdateAttr(props) {
}).done(function(data, textStatue, jqXHR) {
if (flash_message) {
var msg = "";
if (user_fail_message) {
if (user_success_message) {
msg = user_success_message;
} else {
msg = default_success_message;
......@@ -635,7 +635,7 @@ jumpserver.initServerSideDataTable = function (options) {
columns: options.columns || [],
select: options.select || select,
language: jumpserver.language,
lengthMenu: [[15, 25, 50, 9999], [15, 25, 50, 'All']]
lengthMenu: options.lengthMenu || [[15, 25, 50, 9999], [15, 25, 50, 'All']]
});
table.selected = [];
table.selected_rows = [];
......@@ -1072,3 +1072,27 @@ function htmlEscape ( d ) {
d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
d;
}
function objectAttrsIsList(obj, attrs) {
attrs.forEach(function (attr) {
if (obj[attr] && !(obj[attr] instanceof Array)){
obj[attr] = [obj[attr]]
}
})
}
function objectAttrsIsDatetime(obj, attrs) {
attrs.forEach(function (attr) {
obj[attr] = new Date(obj[attr]).toISOString();
})
}
function objectAttrsIsBool(obj, attrs) {
attrs.forEach(function (attr) {
if (!obj[attr]) {
obj[attr] = false
} else if (['on', '1'].includes(obj[attr])) {
obj[attr] = true
}
})
}
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