Merge pull request #1213 from jumpserver/dev

更新资产选择
pull/2666/head 1.2.1
老广 2018-04-19 10:49:01 +08:00 committed by GitHub
commit 53c532a6ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 686 additions and 530 deletions

View File

@ -32,6 +32,7 @@ __all__ = [
'NodeViewSet', 'NodeChildrenApi', 'NodeViewSet', 'NodeChildrenApi',
'NodeAssetsApi', 'NodeWithAssetsApi', 'NodeAssetsApi', 'NodeWithAssetsApi',
'NodeAddAssetsApi', 'NodeRemoveAssetsApi', 'NodeAddAssetsApi', 'NodeRemoveAssetsApi',
'NodeReplaceAssetsApi',
'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi', 'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi',
'TestNodeConnectiveApi' 'TestNodeConnectiveApi'
] ]
@ -191,6 +192,19 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView):
instance.assets.remove(*tuple(assets)) instance.assets.remove(*tuple(assets))
class NodeReplaceAssetsApi(generics.UpdateAPIView):
serializer_class = serializers.NodeAssetsSerializer
queryset = Node.objects.all()
permission_classes = (IsSuperUser,)
instance = None
def perform_update(self, serializer):
assets = serializer.validated_data.get('assets')
instance = self.get_object()
for asset in assets:
asset.nodes.set([instance])
class RefreshNodeHardwareInfoApi(APIView): class RefreshNodeHardwareInfoApi(APIView):
permission_classes = (IsSuperUser,) permission_classes = (IsSuperUser,)
model = Node model = Node

View File

@ -49,6 +49,7 @@ class Asset(models.Model):
ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True) ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname')) hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname'))
port = models.IntegerField(default=22, verbose_name=_('Port')) port = models.IntegerField(default=22, verbose_name=_('Port'))
platform = models.CharField(max_length=128, choices=PLATFORM_CHOICES, default='Linux', verbose_name=_('Platform'))
domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"), on_delete=models.SET_NULL) domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"), on_delete=models.SET_NULL)
nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes")) nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes"))
is_active = models.BooleanField(default=True, verbose_name=_('Is active')) is_active = models.BooleanField(default=True, verbose_name=_('Is active'))
@ -72,7 +73,6 @@ class Asset(models.Model):
disk_total = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk total')) disk_total = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk total'))
disk_info = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk info')) disk_info = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('Disk info'))
platform = models.CharField(max_length=128, choices=PLATFORM_CHOICES, default='Linux', verbose_name=_('Platform'))
os = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('OS')) os = models.CharField(max_length=128, null=True, blank=True, verbose_name=_('OS'))
os_version = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('OS version')) os_version = models.CharField(max_length=16, null=True, blank=True, verbose_name=_('OS version'))
os_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('OS arch')) os_arch = models.CharField(max_length=16, blank=True, null=True, verbose_name=_('OS arch'))

View File

@ -19,7 +19,7 @@ class Node(models.Model):
is_asset = False is_asset = False
def __str__(self): def __str__(self):
return self.value return self.full_value
@property @property
def name(self): def name(self):
@ -30,7 +30,7 @@ class Node(models.Model):
if self == self.__class__.root(): if self == self.__class__.root():
return self.value return self.value
else: else:
return '{}/{}'.format(self.value, self.parent.full_value) return '{} / {}'.format(self.parent.full_value, self.value)
@property @property
def level(self): def level(self):

View File

@ -96,6 +96,9 @@ def update_assets_hardware_info_util(assets, task_name=None):
task_name = _("更新资产硬件信息") task_name = _("更新资产硬件信息")
tasks = const.UPDATE_ASSETS_HARDWARE_TASKS tasks = const.UPDATE_ASSETS_HARDWARE_TASKS
hostname_list = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()] hostname_list = [asset.hostname for asset in assets if asset.is_active and asset.is_unixlike()]
if not hostname_list:
logger.info("Not hosts get, may be asset is not active or not unixlike platform")
return {}
task, created = update_or_create_ansible_task( task, created = update_or_create_ansible_task(
task_name, hosts=hostname_list, tasks=tasks, pattern='all', task_name, hosts=hostname_list, tasks=tasks, pattern='all',
options=const.TASK_OPTIONS, run_as_admin=True, created_by='System', options=const.TASK_OPTIONS, run_as_admin=True, created_by='System',

View File

@ -1,132 +1,125 @@
{% extends '_modal.html' %} {% extends '_modal.html' %}
{% load i18n %} {% load i18n %}
{% load static %}
{% block modal_class %}modal-lg{% endblock %} {% block modal_class %}modal-lg{% endblock %}
{% block modal_id %}asset_list_modal{% endblock %} {% block modal_id %}asset_list_modal{% endblock %}
{#{% block modal_title%}{% trans "Please select assets" %}{% endblock %}#} {% block modal_title%}{% trans "Asset list" %}{% endblock %}
{% block modal_body %} {% block modal_body %}
{#<div class="btn-group" style="float: right">#} <link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet">
{# <button data-toggle="dropdown" class="btn btn-default btn-sm dropdown-toggle">{% trans 'Label' %} <span class="caret"></span></button>#} <script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script>
{# <ul class="dropdown-menu labels">#} <script src="{% static 'js/jquery.form.min.js' %}"></script>
{# {% for label in labels %}#} <style>
{# <li><a style="font-weight: bolder">{{ label.name }}:{{ label.value }}</a></li>#} .inmodal .modal-header {
{# {% endfor %}#} padding: 10px 10px;
{# </ul>#} text-align: center;
{#</div>#} }
<table class="table table-striped table-bordered table-hover " id="asset_modal_table" width="100%">
<thead> #assetTree2.ztree * {
<tr> background-color: #f8fafb;
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th> }
<th class="text-center">{% trans 'Hostname' %}</th> #assetTree2.ztree {
<th class="text-center">{% trans 'IP' %}</th> background-color: #f8fafb;
<th class="text-center">{% trans 'Hardware' %}</th> }
<th class="text-center">{% trans 'Active' %}</th> </style>
<th class="text-center">{% trans 'Reachable' %}</th>
<th class="text-center">{% trans 'Action' %}</th> <div class="wrapper wrapper-content">
</tr> <div class="row">
</thead> <div class="col-lg-3" id="split-left" style="padding-left: 3px">
<tbody> <div class="ibox float-e-margins">
</tbody> <div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
</table> <div class="file-manager ">
<div id="actions" class="hide"> <div id="assetTree2" class="ztree">
<div class="input-group"> </div>
<select class="form-control m-b" style="width: auto" id="slct_bulk_update"> <div class="clearfix"></div>
<option value="delete">{% trans 'Delete selected' %}</option> </div>
<option value="update">{% trans 'Update selected' %}</option> </div>
<option value="deactive">{% trans 'Deactive selected' %}</option> </div>
<option value="active">{% trans 'Active selected' %}</option> </div>
</select> <div class="col-lg-9 animated fadeInRight" id="split-right">
<div class="input-group-btn pull-left" style="padding-left: 5px;"> <div class="mail-box-header">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary"> <table class="table table-striped table-bordered table-hover " id="asset_list_modal_table" style="width: 100%">
{% trans 'Submit' %} <thead>
</button> <tr>
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
<th class="text-center">{% trans 'Hostname' %}</th>
<th class="text-center">{% trans 'IP' %}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
var zTree2, asset_table2 = 0;
var modal_table; function initTable2() {
function initModalTable() {
var options = { var options = {
ele: $('#asset_modal_table'), ele: $('#asset_list_modal_table'),
columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 3, createdCell: function (td, cellData, rowData) {
$(td).html(rowData.hardware_info)
}},
{targets: 4, createdCell: function (td, cellData) {
if (!cellData) {
$(td).html('<i class="fa fa-times text-danger"></i>')
} else {
$(td).html('<i class="fa fa-check text-navy"></i>')
}
}},
{targets: 5, createdCell: function (td, cellData) {
if (cellData === 'Unknown'){
$(td).html('<i class="fa fa-circle text-warning"></i>')
} else if (!cellData) {
$(td).html('<i class="fa fa-circle text-danger"></i>')
} else {
$(td).html('<i class="fa fa-circle text-navy"></i>')
}
}},
{targets: 6, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:asset-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_asset_delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn)
}}
],
ajax_url: '{% url "api-assets:asset-list" %}', ajax_url: '{% url "api-assets:asset-list" %}',
columns: [ columns: [
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "id"}, {data: "hostname" }, {data: "ip" }
{data: "cpu_cores"}, {data: "is_active", orderable: false },
{data: "is_connective", orderable: false}, {data: "id", orderable: false }
], ],
op_html: $('#actions').html() pageLength: 10
}; };
modal_table = jumpserver.initServerSideDataTable(options); asset_table2 = jumpserver.initServerSideDataTable(options);
return modal_table; return asset_table2
} }
$(document).ready(function(){ function onSelected2(event, treeNode) {
initModalTable(); var url = asset_table2.ajax.url();
}).on('click', '#btn_select_assets', function () { url = setUrlParam(url, "node_id", treeNode.id);
var data_table = $('#asset_modal_table').DataTable(); setCookie('node_selected', treeNode.id);
var id_list = []; asset_table2.ajax.url(url);
data_table.rows({selected: true}).every(function(){ asset_table2.ajax.reload();
id_list.push(this.data().id); }
function initTree2() {
var setting = {
view: {
dblClickExpand: false,
showLine: true
},
data: {
simpleData: {
enable: true
}
},
callback: {
onSelected: onSelected2
}
};
var zNodes = [];
$.get("{% url 'api-assets:node-list' %}", function(data, status){
$.each(data, function (index, value) {
value["pId"] = value["parent"];
value["open"] = true;
value["name"] = value["value"] + ' (' + value['assets_amount'] + ')';
value['value'] = value['value'];
});
zNodes = data;
$.fn.zTree.init($("#assetTree2"), setting, zNodes);
zTree2 = $.fn.zTree.getZTreeObj("assetTree2");
}); });
var current_node; }
var nodes = zTree.getSelectedNodes();
if (nodes && nodes.length === 1) {
current_node = nodes[0]
} else {
return
}
var data = {
'assets': id_list
};
var success = function () { $(document).ready(function(){
modal_table.ajax.reload() initTable2();
}; initTree2();
APIUpdateAttr({
'url': '/api/assets/v1/nodes/' + current_node.id + '/assets/add/',
'method': 'PUT',
'body': JSON.stringify(data),
'success': success
})
}) })
</script> </script>
{% endblock %} {% endblock %}
{% block modal_confirm_id %}btn_select_assets{% endblock %}
{% block modal_button %}
{{ block.super }}
{% endblock %}
{% block modal_confirm_id %}btn_asset_modal_confirm{% endblock %}

View File

@ -305,9 +305,9 @@ $(document).ready(function () {
success_message: success success_message: success
}); });
if (status === "False") { if (status === "False") {
$(".ibox-content > table > tbody > tr:nth-child(13) > td:last >b").html('True'); $(".ibox-content > table > tbody > tr:nth-child(13) > td:last >b").html('True');
}else{ }else{
$(".ibox-content > table > tbody > tr:nth-child(13) > td:last >b").html('False'); $(".ibox-content > table > tbody > tr:nth-child(13) > td:last >b").html('False');
} }
}).on('click', '#btn-update-nodes', function () { }).on('click', '#btn-update-nodes', function () {
if (Object.keys(jumpserver.nodes_selected).length === 0) { if (Object.keys(jumpserver.nodes_selected).length === 0) {

View File

@ -59,57 +59,57 @@
<i class="fa fa-angle-left fa-x" id="toggle-icon"></i> <i class="fa fa-angle-left fa-x" id="toggle-icon"></i>
</div> </div>
</div> </div>
<div class="mail-box-header"> <div class="mail-box-header">
<div class="uc pull-left m-r-5"><a class="btn btn-sm btn-primary btn-create-asset"> {% trans "Create asset" %} </a></div> <div class="uc pull-left m-r-5"><a class="btn btn-sm btn-primary btn-create-asset"> {% trans "Create asset" %} </a></div>
<div class="html5buttons"> <div class="html5buttons">
<div class="dt-buttons btn-group"> <div class="dt-buttons btn-group">
<a class="btn btn-default btn_import" data-toggle="modal" data-target="#asset_import_modal" tabindex="0"> <a class="btn btn-default btn_import" data-toggle="modal" data-target="#asset_import_modal" tabindex="0">
<span>{% trans "Import" %}</span> <span>{% trans "Import" %}</span>
</a> </a>
<a class="btn btn-default btn_export" tabindex="0"> <a class="btn btn-default btn_export" tabindex="0">
<span>{% trans "Export" %}</span> <span>{% trans "Export" %}</span>
</a> </a>
</div>
</div>
<div class="btn-group" style="float: right">
<button data-toggle="dropdown" class="btn btn-default btn-sm dropdown-toggle">{% trans 'Label' %} <span class="caret"></span></button>
<ul class="dropdown-menu labels">
{% for label in labels %}
<li><a style="font-weight: bolder">{{ label.name }}:{{ label.value }}</a></li>
{% endfor %}
</ul>
</div> </div>
<table class="table table-striped table-bordered table-hover " id="asset_list_table" style="width: 100%"> </div>
<thead> <div class="btn-group" style="float: right">
<tr> <button data-toggle="dropdown" class="btn btn-default btn-sm dropdown-toggle">{% trans 'Label' %} <span class="caret"></span></button>
<th class="text-center"><input type="checkbox" class="ipt_check_all"></th> <ul class="dropdown-menu labels">
<th class="text-center">{% trans 'Hostname' %}</th> {% for label in labels %}
<th class="text-center">{% trans 'IP' %}</th> <li><a style="font-weight: bolder">{{ label.name }}:{{ label.value }}</a></li>
<th class="text-center">{% trans 'Hardware' %}</th> {% endfor %}
<th class="text-center">{% trans 'Active' %}</th> </ul>
<th class="text-center">{% trans 'Reachable' %}</th> </div>
<th class="text-center">{% trans 'Action' %}</th> <table class="table table-striped table-bordered table-hover " id="asset_list_table" style="width: 100%">
</tr> <thead>
</thead> <tr>
<tbody> <th class="text-center"><input type="checkbox" class="ipt_check_all"></th>
</tbody> <th class="text-center">{% trans 'Hostname' %}</th>
</table> <th class="text-center">{% trans 'IP' %}</th>
<div id="actions" class="hide"> <th class="text-center">{% trans 'Hardware' %}</th>
<div class="input-group"> <th class="text-center">{% trans 'Active' %}</th>
<select class="form-control m-b" style="width: auto" id="slct_bulk_update"> <th class="text-center">{% trans 'Reachable' %}</th>
<option value="delete">{% trans 'Delete selected' %}</option> <th class="text-center">{% trans 'Action' %}</th>
<option value="update">{% trans 'Update selected' %}</option> </tr>
<option value="remove">{% trans 'Remove from this node' %}</option> </thead>
<option value="deactive">{% trans 'Deactive selected' %}</option> <tbody>
<option value="active">{% trans 'Active selected' %}</option> </tbody>
</select> </table>
<div class="input-group-btn pull-left" style="padding-left: 5px;"> <div id="actions" class="hide">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary"> <div class="input-group">
{% trans 'Submit' %} <select class="form-control m-b" style="width: auto" id="slct_bulk_update">
</button> <option value="delete">{% trans 'Delete selected' %}</option>
</div> <option value="update">{% trans 'Update selected' %}</option>
<option value="remove">{% trans 'Remove from this node' %}</option>
<option value="deactive">{% trans 'Deactive selected' %}</option>
<option value="active">{% trans 'Active selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div> </div>
</div> </div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -117,15 +117,16 @@
<div id="rMenu"> <div id="rMenu">
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li id="menu_asset_create" class="btn-create-asset" tabindex="-1"><a>{% trans 'Create asset' %}</a></li>
<li id="menu_asset_add" class="btn-add-asset" data-toggle="modal" data-target="#asset_list_modal" tabindex="0"><a>{% trans 'Add asset' %}</a></li>
<li id="menu_refresh_hardware_info" class="btn-refresh-hardware" tabindex="-1"><a>{% trans 'Refresh node hardware info' %}</a></li>
<li id="menu_test_connective" class="btn-test-connective" tabindex="-1"><a>{% trans 'Test node connective' %}</a></li>
<li class="divider"></li> <li class="divider"></li>
<li id="m_create" tabindex="-1" onclick="addTreeNode();"><a>{% trans 'Add node' %}</a></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>{% trans 'Rename 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 class="divider"></li>
<li id="m_del" tabindex="-1" onclick="removeTreeNode();"><a>{% trans 'Delete node' %}</a></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>
</ul> </ul>
</div> </div>
@ -136,6 +137,7 @@
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
var zTree, rMenu, asset_table, show = 0; var zTree, rMenu, asset_table, show = 0;
var update_node_action = "";
function initTable() { function initTable() {
var options = { var options = {
ele: $('#asset_list_table'), ele: $('#asset_list_table'),
@ -210,10 +212,11 @@ function removeTreeNode() {
if (!current_node){ if (!current_node){
return return
} }
if (current_node.children && current_node.children.length > 0) { if (current_node.children && current_node.children.length > 0) {
alert("{% trans 'Have child node, cancel' %}") toastr.error("{% trans 'Have child node, cancel' %}");
} else { } else if (current_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 ); var url = "{% url 'api-assets:node-detail' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node.id );
$.ajax({ $.ajax({
url: url, url: url,
@ -249,13 +252,6 @@ function OnRightClick(event, treeId, treeNode) {
function showRMenu(type, x, y) { function showRMenu(type, x, y) {
$("#rMenu ul").show(); $("#rMenu ul").show();
{#if (type === "root") {#}
{# return#}
{# } else {#}
{# $("#m_del").show();#}
{# $("#m_check").show();#}
{# $("#m_unCheck").show();#}
{# }#}
x -= 220; x -= 220;
rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"}); rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"});
@ -459,7 +455,8 @@ $(document).ready(function(){
var current_node; var current_node;
if (nodes && nodes.length ===1 ){ if (nodes && nodes.length ===1 ){
current_node = nodes[0]; current_node = nodes[0];
action += "?node_id=" + current_node.id; action = setUrlParam(action, 'node_id', current_node.id);
{#action += "?node_id=" + current_node.id;#}
$form.attr("action", action) $form.attr("action", action)
} }
$form.find('.help-block').remove(); $form.find('.help-block').remove();
@ -673,7 +670,45 @@ $(document).ready(function(){
break; break;
} }
$(".ipt_check_all").prop("checked", false) $(".ipt_check_all").prop("checked", false)
}); })
.on('click', '#btn_asset_modal_confirm', function () {
var assets_selected = asset_table2.selected;
var current_node;
var nodes = zTree.getSelectedNodes();
if (nodes && nodes.length === 1) {
current_node = nodes[0]
} else {
return
}
var data = {
'assets': assets_selected
};
var success = function () {
asset_table2.selected = [];
asset_table2.ajax.reload()
};
var url = '';
if (update_node_action === "move") {
url = "{% url 'api-assets:node-replace-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node.id);
} else {
url = "{% url 'api-assets:node-add-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node.id);
}
APIUpdateAttr({
'url': url,
'method': 'PUT',
'body': JSON.stringify(data),
'success': success
})
}).on('hidden.bs.modal', '#asset_list_modal', function () {
window.location.reload();
}).on('click', '#menu_asset_add', function () {
update_node_action = "add"
}).on('click', '#menu_asset_move', function () {
update_node_action = "move"
})
</script> </script>
{% endblock %} {% endblock %}

View File

@ -18,14 +18,25 @@
</div> </div>
</div> </div>
</form> </form>
{% include 'assets/_asset_list_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2({ console.log($.fn.select2.defaults);
closeOnSelect: false $('.select2').select2().off("select2:open");
}); }).on('click', '.select2-selection__rendered', function (e) {
e.preventDefault();
$("#asset_list_modal").modal();
})
.on('click', '#btn_asset_modal_confirm', function () {
var assets = asset_table2.selected;
$.each(assets, function (id, data) {
$('.select2').val(assets).trigger('change');
}); });
$("#asset_list_modal").modal('hide');
})
</script> </script>
{% endblock %} {% endblock %}

View File

@ -81,11 +81,6 @@ function initTable() {
var options = { var options = {
ele: $('#domain_list_table'), ele: $('#domain_list_table'),
columnDefs: [ columnDefs: [
{targets: 1, createdCell: function (td, cellData, rowData) {
var detail_btn = '<a href="{% url "assets:domain-detail" pk=DEFAULT_PK %}">' + cellData + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
}},
{targets: 7, createdCell: function (td, cellData, rowData) { {targets: 7, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var update_btn = '<a href="{% url "assets:domain-gateway-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-uid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);

View File

@ -3,6 +3,8 @@
{% load bootstrap3 %} {% load bootstrap3 %}
{% load i18n %} {% load i18n %}
{% block form %} {% block form %}
<form id="groupForm" method="post" class="form-horizontal"> <form id="groupForm" method="post" class="form-horizontal">
{% csrf_token %} {% csrf_token %}
@ -18,14 +20,28 @@
</div> </div>
</div> </div>
</form> </form>
{% include 'assets/_asset_list_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2({ $('.select2').select2({
closeOnSelect: false closeOnSelect: false
}); })
}).on('click', '.select2-selection__rendered', function (e) {
e.preventDefault();
$("#asset_list_modal").modal();
})
.on('click', '#btn_asset_modal_confirm', function () {
var assets = asset_table2.selected;
$('.select2 option:selected').each(function (i, data) {
assets.push($(data).attr('value'))
}); });
$.each(assets, function (id, data) {
$('.select2').val(assets).trigger('change');
});
$("#asset_list_modal").modal('hide');
})
</script> </script>
{% endblock %} {% endblock %}

View File

@ -173,7 +173,7 @@
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Add to node' %}" id="node_selected" class="select2" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Add to node' %}" id="node_selected" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for node in nodes_remain %} {% for node in nodes_remain %}
<option value="{{ node.id }}" id="opt_{{ node.id }}" >{{ node.name }}</option> <option value="{{ node.id }}" id="opt_{{ node.id }}" >{{ node }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
@ -187,7 +187,7 @@
{% for node in system_user.nodes.all %} {% for node in system_user.nodes.all %}
<tr> <tr>
<td ><b class="bdg_node" data-gid={{ node.id }}>{{ node.name }}</b></td> <td ><b class="bdg_node" data-gid={{ node.id }}>{{ node }}</b></td>
<td> <td>
<button class="btn btn-danger pull-right btn-xs btn-remove-from-node" type="button"><i class="fa fa-minus"></i></button> <button class="btn btn-danger pull-right btn-xs btn-remove-from-node" type="button"><i class="fa fa-minus"></i></button>
</td> </td>

View File

@ -40,6 +40,7 @@ urlpatterns = [
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/add/$', api.NodeAddChildrenApi.as_view(), name='node-add-children'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/children/add/$', api.NodeAddChildrenApi.as_view(), name='node-add-children'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.NodeAssetsApi.as_view(), name='node-assets'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.NodeAssetsApi.as_view(), name='node-assets'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$', api.NodeAddAssetsApi.as_view(), name='node-add-assets'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/add/$', api.NodeAddAssetsApi.as_view(), name='node-add-assets'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/replace/$', api.NodeReplaceAssetsApi.as_view(), name='node-replace-assets'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/assets/remove/$', api.NodeRemoveAssetsApi.as_view(), name='node-remove-assets'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$', api.RefreshNodeHardwareInfoApi.as_view(), name='node-refresh-hardware-info'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/refresh-hardware-info/$', api.RefreshNodeHardwareInfoApi.as_view(), name='node-refresh-hardware-info'),
url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$', api.TestNodeConnectiveApi.as_view(), name='node-test-connective'), url(r'^v1/nodes/(?P<pk>[0-9a-zA-Z\-]{36})/test-connective/$', api.TestNodeConnectiveApi.as_view(), name='node-test-connective'),

View File

@ -49,6 +49,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
'app': _('Assets'), 'app': _('Assets'),
'action': _('Asset list'), 'action': _('Asset list'),
'labels': Label.objects.all().order_by('name'), 'labels': Label.objects.all().order_by('name'),
'nodes': Node.objects.all().order_by('-key'),
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
@ -284,24 +285,26 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
if set(row) == {''}: if set(row) == {''}:
continue continue
asset_dict = dict(zip(attr, row)) asset_dict_raw = dict(zip(attr, row))
id_ = asset_dict.pop('id', 0) asset_dict = dict()
for k, v in asset_dict.items(): for k, v in asset_dict_raw.items():
v = v.strip() v = v.strip()
if k == 'is_active': if k == 'is_active':
v = True if v in ['TRUE', 1, 'true'] else False v = False if v in ['False', 0, 'false'] else True
elif k == 'admin_user': elif k == 'admin_user':
v = get_object_or_none(AdminUser, name=v) v = get_object_or_none(AdminUser, name=v)
elif k in ['port', 'cpu_count', 'cpu_cores']: elif k in ['port', 'cpu_count', 'cpu_cores']:
try: try:
v = int(v) v = int(v)
except ValueError: except ValueError:
v = 0 v = ''
elif k == 'domain': elif k == 'domain':
v = get_object_or_none(Domain, name=v) v = get_object_or_none(Domain, name=v)
asset_dict[k] = v
asset = get_object_or_none(Asset, id=id_) if is_uuid(id_) else None if v != '':
asset_dict[k] = v
asset = get_object_or_none(Asset, id=asset_dict.pop('id', 0))
if not asset: if not asset:
try: try:
if len(Asset.objects.filter(hostname=asset_dict.get('hostname'))): if len(Asset.objects.filter(hostname=asset_dict.get('hostname'))):
@ -316,7 +319,7 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
failed.append('%s: %s' % (asset_dict['hostname'], str(e))) failed.append('%s: %s' % (asset_dict['hostname'], str(e)))
else: else:
for k, v in asset_dict.items(): for k, v in asset_dict.items():
if v: if v != '':
setattr(asset, k, v) setattr(asset, k, v)
try: try:
asset.save() asset.save()

View File

@ -2,11 +2,15 @@
# #
import json import json
from django.db import models
from django import forms from django import forms
from django.utils import six from django.utils import six
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from rest_framework import serializers from rest_framework import serializers
from .utils import get_signer
signer = get_signer()
class DictField(forms.Field): class DictField(forms.Field):
@ -46,4 +50,27 @@ class StringIDField(serializers.Field):
class StringManyToManyField(serializers.RelatedField): class StringManyToManyField(serializers.RelatedField):
def to_representation(self, value): def to_representation(self, value):
return value.__str__() return value.__str__()
class EncryptMixin:
def from_db_value(self, value, expression, connection, context):
if value is not None:
return signer.unsign(value)
return super().from_db_value(self, value, expression, connection, context)
def get_prep_value(self, value):
if value is None:
return value
return signer.sign(value).decode('utf-8')
class EncryptTextField(EncryptMixin, models.TextField):
description = _("Encrypt field using Secret Key")
class EncryptCharField(EncryptMixin, models.CharField):
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 2048
super().__init__(*args, **kwargs)

Binary file not shown.

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n" "Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-11 15:13+0800\n" "POT-Creation-Date: 2018-04-13 17:27+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n" "Language-Team: Jumpserver team<ibuler@qq.com>\n"
@ -17,19 +17,19 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: assets/api/node.py:87 #: assets/api/node.py:88
msgid "New node {}" msgid "New node {}"
msgstr "新节点 {}" msgstr "新节点 {}"
#: assets/api/node.py:202 #: assets/api/node.py:216
msgid "更新节点资产硬件信息: {}" msgid "更新节点资产硬件信息: {}"
msgstr "" msgstr ""
#: assets/api/node.py:215 #: assets/api/node.py:229
msgid "测试节点下资产是否可连接: {}" msgid "测试节点下资产是否可连接: {}"
msgstr "" msgstr ""
#: assets/forms/asset.py:24 assets/models/asset.py:53 assets/models/user.py:103 #: assets/forms/asset.py:24 assets/models/asset.py:54 assets/models/user.py:103
#: assets/templates/assets/asset_detail.html:183 #: assets/templates/assets/asset_detail.html:183
#: assets/templates/assets/asset_detail.html:191 #: assets/templates/assets/asset_detail.html:191
#: assets/templates/assets/system_user_detail.html:166 perms/models.py:23 #: assets/templates/assets/system_user_detail.html:166 perms/models.py:23
@ -37,7 +37,7 @@ msgid "Nodes"
msgstr "节点管理" msgstr "节点管理"
#: assets/forms/asset.py:27 assets/forms/asset.py:66 assets/forms/asset.py:109 #: assets/forms/asset.py:27 assets/forms/asset.py:66 assets/forms/asset.py:109
#: assets/forms/asset.py:113 assets/models/asset.py:57 #: assets/forms/asset.py:113 assets/models/asset.py:58
#: assets/models/cluster.py:19 assets/models/user.py:72 #: assets/models/cluster.py:19 assets/models/user.py:72
#: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25 #: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25
msgid "Admin user" msgid "Admin user"
@ -53,7 +53,7 @@ msgstr "管理用户"
msgid "Label" msgid "Label"
msgstr "标签" msgstr "标签"
#: assets/forms/asset.py:34 assets/forms/asset.py:73 assets/models/asset.py:52 #: assets/forms/asset.py:34 assets/forms/asset.py:73 assets/models/asset.py:53
#: assets/models/domain.py:46 #: assets/models/domain.py:46
msgid "Domain" msgid "Domain"
msgstr "网域" msgstr "网域"
@ -201,7 +201,7 @@ msgid ""
msgstr "高优先级的系统用户将会作为默认登录用户" msgstr "高优先级的系统用户将会作为默认登录用户"
#: assets/models/asset.py:49 assets/models/domain.py:43 #: assets/models/asset.py:49 assets/models/domain.py:43
#: assets/templates/assets/_asset_list_modal.html:21 #: assets/templates/assets/_asset_list_modal.html:46
#: assets/templates/assets/admin_user_assets.html:52 #: assets/templates/assets/admin_user_assets.html:52
#: assets/templates/assets/asset_detail.html:61 #: assets/templates/assets/asset_detail.html:61
#: assets/templates/assets/asset_list.html:87 #: assets/templates/assets/asset_list.html:87
@ -215,7 +215,7 @@ msgstr "高优先级的系统用户将会作为默认登录用户"
msgid "IP" msgid "IP"
msgstr "IP" msgstr "IP"
#: assets/models/asset.py:50 assets/templates/assets/_asset_list_modal.html:20 #: assets/models/asset.py:50 assets/templates/assets/_asset_list_modal.html:45
#: assets/templates/assets/admin_user_assets.html:51 #: assets/templates/assets/admin_user_assets.html:51
#: assets/templates/assets/asset_detail.html:57 #: assets/templates/assets/asset_detail.html:57
#: assets/templates/assets/asset_list.html:86 #: assets/templates/assets/asset_list.html:86
@ -227,59 +227,59 @@ msgstr "IP"
msgid "Hostname" msgid "Hostname"
msgstr "主机名" msgstr "主机名"
#: assets/models/asset.py:54 assets/models/domain.py:48 #: assets/models/asset.py:52 assets/templates/assets/asset_detail.html:97
msgid "Platform"
msgstr "系统平台"
#: assets/models/asset.py:55 assets/models/domain.py:48
#: assets/models/label.py:20 assets/templates/assets/asset_detail.html:105 #: assets/models/label.py:20 assets/templates/assets/asset_detail.html:105
msgid "Is active" msgid "Is active"
msgstr "激活" msgstr "激活"
#: assets/models/asset.py:60 assets/templates/assets/asset_detail.html:65 #: assets/models/asset.py:61 assets/templates/assets/asset_detail.html:65
msgid "Public IP" msgid "Public IP"
msgstr "公网IP" msgstr "公网IP"
#: assets/models/asset.py:61 assets/templates/assets/asset_detail.html:113 #: assets/models/asset.py:62 assets/templates/assets/asset_detail.html:113
msgid "Asset number" msgid "Asset number"
msgstr "资产编号" msgstr "资产编号"
#: assets/models/asset.py:64 assets/templates/assets/asset_detail.html:77 #: assets/models/asset.py:65 assets/templates/assets/asset_detail.html:77
msgid "Vendor" msgid "Vendor"
msgstr "制造商" msgstr "制造商"
#: assets/models/asset.py:65 assets/templates/assets/asset_detail.html:81 #: assets/models/asset.py:66 assets/templates/assets/asset_detail.html:81
msgid "Model" msgid "Model"
msgstr "型号" msgstr "型号"
#: assets/models/asset.py:66 assets/templates/assets/asset_detail.html:109 #: assets/models/asset.py:67 assets/templates/assets/asset_detail.html:109
msgid "Serial number" msgid "Serial number"
msgstr "序列号" msgstr "序列号"
#: assets/models/asset.py:68 #: assets/models/asset.py:69
msgid "CPU model" msgid "CPU model"
msgstr "CPU型号" msgstr "CPU型号"
#: assets/models/asset.py:69 #: assets/models/asset.py:70
msgid "CPU count" msgid "CPU count"
msgstr "CPU数量" msgstr "CPU数量"
#: assets/models/asset.py:70 #: assets/models/asset.py:71
msgid "CPU cores" msgid "CPU cores"
msgstr "CPU核数" msgstr "CPU核数"
#: assets/models/asset.py:71 assets/templates/assets/asset_detail.html:89 #: assets/models/asset.py:72 assets/templates/assets/asset_detail.html:89
msgid "Memory" msgid "Memory"
msgstr "内存" msgstr "内存"
#: assets/models/asset.py:72 #: assets/models/asset.py:73
msgid "Disk total" msgid "Disk total"
msgstr "硬盘大小" msgstr "硬盘大小"
#: assets/models/asset.py:73 #: assets/models/asset.py:74
msgid "Disk info" msgid "Disk info"
msgstr "硬盘信息" msgstr "硬盘信息"
#: assets/models/asset.py:75 assets/templates/assets/asset_detail.html:97
msgid "Platform"
msgstr "系统平台"
#: assets/models/asset.py:76 assets/templates/assets/asset_detail.html:101 #: assets/models/asset.py:76 assets/templates/assets/asset_detail.html:101
msgid "OS" msgid "OS"
msgstr "操作系统" msgstr "操作系统"
@ -454,8 +454,8 @@ msgstr ""
#: assets/views/admin_user.py:29 assets/views/admin_user.py:47 #: assets/views/admin_user.py:29 assets/views/admin_user.py:47
#: assets/views/admin_user.py:63 assets/views/admin_user.py:78 #: assets/views/admin_user.py:63 assets/views/admin_user.py:78
#: assets/views/admin_user.py:102 assets/views/asset.py:49 #: assets/views/admin_user.py:102 assets/views/asset.py:49
#: assets/views/asset.py:95 assets/views/asset.py:155 assets/views/asset.py:172 #: assets/views/asset.py:96 assets/views/asset.py:156 assets/views/asset.py:173
#: assets/views/asset.py:196 assets/views/domain.py:29 #: assets/views/asset.py:197 assets/views/domain.py:29
#: assets/views/domain.py:45 assets/views/domain.py:61 #: assets/views/domain.py:45 assets/views/domain.py:61
#: assets/views/domain.py:74 assets/views/domain.py:98 #: assets/views/domain.py:74 assets/views/domain.py:98
#: assets/views/domain.py:126 assets/views/domain.py:150 #: assets/views/domain.py:126 assets/views/domain.py:150
@ -504,38 +504,66 @@ msgstr "系统用户"
msgid "%(value)s is not an even number" msgid "%(value)s is not an even number"
msgstr "%(value)s is not an even number" msgstr "%(value)s is not an even number"
#: assets/tasks.py:96 assets/tasks.py:113 #: assets/tasks.py:96 assets/tasks.py:116
msgid "更新资产硬件信息" msgid "更新资产硬件信息"
msgstr "" msgstr ""
#: assets/tasks.py:132 #: assets/tasks.py:135
msgid "定期更新资产硬件信息" msgid "定期更新资产硬件信息"
msgstr "" msgstr ""
#: assets/tasks.py:210 #: assets/tasks.py:213
msgid "定期测试管理账号可连接性: {}" msgid "定期测试管理账号可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:217 #: assets/tasks.py:220
msgid "测试管理行号可连接性: {}" msgid "测试管理行号可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:227 #: assets/tasks.py:230
msgid "测试资产可连接性" msgid "测试资产可连接性"
msgstr "" msgstr ""
#: assets/tasks.py:297 #: assets/tasks.py:300
msgid "Test system user connectability: {}" msgid "Test system user connectability: {}"
msgstr "测试系统用户可连接性: {}" msgstr "测试系统用户可连接性: {}"
#: assets/tasks.py:313 #: assets/tasks.py:316
msgid "定期测试系统用户可连接性: {}" msgid "定期测试系统用户可连接性: {}"
msgstr "" msgstr ""
#: assets/tasks.py:398 #: assets/tasks.py:401
msgid "推送系统用户到入资产: {}" msgid "推送系统用户到入资产: {}"
msgstr "" msgstr ""
#: assets/templates/assets/_admin_user_setting_modal.html:4
#: users/templates/users/reset_password.html:57
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgstr "设置"
#: assets/templates/assets/_admin_user_setting_modal.html:9
#: assets/templates/assets/_asset_import_modal.html:9
#: users/templates/users/_user_import_modal.html:10
msgid "Template"
msgstr "模板"
#: assets/templates/assets/_admin_user_setting_modal.html:10
#: assets/templates/assets/_asset_import_modal.html:10
#: users/templates/users/_user_import_modal.html:11
msgid "Download"
msgstr "下载"
#: assets/templates/assets/_admin_user_setting_modal.html:13
#: assets/templates/assets/_asset_import_modal.html:13
msgid "Asset csv file"
msgstr "资产csv文件"
#: assets/templates/assets/_admin_user_setting_modal.html:16
#: assets/templates/assets/_asset_import_modal.html:16
msgid "If set id, will use this id update asset existed"
msgstr "如果设置了id则会使用该行信息更新该id的资产"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:5 #: assets/templates/assets/_asset_group_bulk_update_modal.html:5
msgid "Update asset group" msgid "Update asset group"
msgstr "更新用户组" msgstr "更新用户组"
@ -566,174 +594,10 @@ msgstr "二次验证"
msgid "Import asset" msgid "Import asset"
msgstr "导入资产" msgstr "导入资产"
#: assets/templates/assets/_asset_import_modal.html:9 #: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:50
#: users/templates/users/_user_import_modal.html:10 #: templates/_nav.html:23
msgid "Template" msgid "Asset list"
msgstr "模板" msgstr "资产列表"
#: assets/templates/assets/_asset_import_modal.html:10
#: users/templates/users/_user_import_modal.html:11
msgid "Download"
msgstr "下载"
#: assets/templates/assets/_asset_import_modal.html:13
msgid "Asset csv file"
msgstr "资产csv文件"
#: assets/templates/assets/_asset_import_modal.html:16
msgid "If set id, will use this id update asset existed"
msgstr "如果设置了id则会使用该行信息更新该id的资产"
#: assets/templates/assets/_asset_list_modal.html:22
#: assets/templates/assets/asset_list.html:88
msgid "Hardware"
msgstr "硬件"
#: assets/templates/assets/_asset_list_modal.html:23
#: assets/templates/assets/asset_detail.html:143
#: assets/templates/assets/asset_list.html:89
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:25
#: perms/models.py:70
#: perms/templates/perms/asset_permission_create_update.html:47
#: perms/templates/perms/asset_permission_detail.html:120
#: perms/templates/perms/asset_permission_list.html:59
#: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/user_detail.html:128
#: users/templates/users/user_granted_asset.html:46
#: users/templates/users/user_group_granted_asset.html:46
#: users/templates/users/user_list.html:27
#: users/templates/users/user_profile.html:63
msgid "Active"
msgstr "激活中"
#: assets/templates/assets/_asset_list_modal.html:24
#: assets/templates/assets/admin_user_assets.html:54
#: assets/templates/assets/admin_user_list.html:26
#: assets/templates/assets/asset_list.html:90
#: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/system_user_list.html:30
#: users/templates/users/user_group_granted_asset.html:47
msgid "Reachable"
msgstr "可连接"
#: assets/templates/assets/_asset_list_modal.html:25
#: assets/templates/assets/admin_user_list.html:30
#: assets/templates/assets/asset_list.html:91
#: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_list.html:18
#: assets/templates/assets/label_list.html:17
#: assets/templates/assets/system_user_list.html:34
#: 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:42
#: perms/templates/perms/asset_permission_list.html:60
#: terminal/templates/terminal/session_list.html:80
#: terminal/templates/terminal/terminal_list.html:36
#: users/templates/users/user_group_list.html:15
#: users/templates/users/user_list.html:28
msgid "Action"
msgstr "动作"
#: assets/templates/assets/_asset_list_modal.html:34
#: assets/templates/assets/asset_list.html:100
#: users/templates/users/user_list.html:37
msgid "Delete selected"
msgstr "批量删除"
#: assets/templates/assets/_asset_list_modal.html:35
#: assets/templates/assets/asset_list.html:101
#: users/templates/users/user_list.html:38
msgid "Update selected"
msgstr "批量更新"
#: assets/templates/assets/_asset_list_modal.html:36
#: assets/templates/assets/asset_list.html:103
#: users/templates/users/user_list.html:39
msgid "Deactive selected"
msgstr "禁用所选"
#: assets/templates/assets/_asset_list_modal.html:37
#: assets/templates/assets/asset_list.html:104
#: users/templates/users/user_list.html:40
msgid "Active selected"
msgstr "激活所选"
#: assets/templates/assets/_asset_list_modal.html:41
#: assets/templates/assets/_system_user.html:71
#: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:67
#: assets/templates/assets/asset_list.html:108
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/label_create_update.html:17
#: common/templates/common/basic_setting.html:59
#: common/templates/common/email_setting.html:60
#: common/templates/common/ldap_setting.html:60
#: common/templates/common/terminal_setting.html:103
#: perms/templates/perms/asset_permission_create_update.html:70
#: terminal/templates/terminal/session_list.html:120
#: terminal/templates/terminal/terminal_update.html:48
#: users/templates/users/_user.html:44
#: users/templates/users/first_login.html:62
#: users/templates/users/forgot_password.html:44
#: users/templates/users/user_bulk_update.html:24
#: users/templates/users/user_list.html:44
#: users/templates/users/user_password_update.html:59
#: users/templates/users/user_profile_update.html:64
#: users/templates/users/user_pubkey_update.html:77
msgid "Submit"
msgstr "提交"
#: assets/templates/assets/_asset_list_modal.html:79
#: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/asset_detail.html:24
#: assets/templates/assets/asset_list.html:168
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:90
#: assets/templates/assets/domain_list.html:42
#: assets/templates/assets/label_list.html:38
#: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:88
#: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:191
#: terminal/templates/terminal/terminal_detail.html:16
#: terminal/templates/terminal/terminal_list.html:71
#: users/templates/users/user_detail.html:25
#: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_list.html:43
#: users/templates/users/user_list.html:76
#: users/templates/users/user_profile.html:135
#: users/templates/users/user_profile.html:143
msgid "Update"
msgstr "更新"
#: assets/templates/assets/_asset_list_modal.html:80
#: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:86
#: assets/templates/assets/asset_detail.html:28
#: assets/templates/assets/asset_list.html:169
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:91
#: assets/templates/assets/domain_list.html:43
#: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:30
#: assets/templates/assets/system_user_list.html:89
#: ops/templates/ops/task_list.html:72
#: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:192
#: terminal/templates/terminal/terminal_list.html:73
#: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32
#: users/templates/users/user_group_list.html:45
#: users/templates/users/user_list.html:80
#: users/templates/users/user_list.html:84
msgid "Delete"
msgstr "删除"
#: assets/templates/assets/_system_user.html:37 #: assets/templates/assets/_system_user.html:37
#: assets/templates/assets/asset_create.html:16 #: assets/templates/assets/asset_create.html:16
@ -790,6 +654,33 @@ msgstr "其它"
msgid "Reset" msgid "Reset"
msgstr "重置" msgstr "重置"
#: assets/templates/assets/_system_user.html:71
#: assets/templates/assets/admin_user_create_update.html:46
#: assets/templates/assets/asset_bulk_update.html:24
#: assets/templates/assets/asset_create.html:67
#: assets/templates/assets/asset_list.html:108
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/label_create_update.html:17
#: common/templates/common/basic_setting.html:59
#: common/templates/common/email_setting.html:60
#: common/templates/common/ldap_setting.html:60
#: common/templates/common/terminal_setting.html:103
#: perms/templates/perms/asset_permission_create_update.html:70
#: terminal/templates/terminal/session_list.html:120
#: terminal/templates/terminal/terminal_update.html:48
#: users/templates/users/_user.html:44
#: users/templates/users/first_login.html:62
#: users/templates/users/forgot_password.html:44
#: users/templates/users/user_bulk_update.html:24
#: users/templates/users/user_list.html:44
#: users/templates/users/user_password_update.html:59
#: users/templates/users/user_profile_update.html:64
#: users/templates/users/user_pubkey_update.html:77
msgid "Submit"
msgstr "提交"
#: assets/templates/assets/admin_user_assets.html:18 #: assets/templates/assets/admin_user_assets.html:18
#: assets/templates/assets/admin_user_detail.html:18 #: assets/templates/assets/admin_user_detail.html:18
#: assets/templates/assets/domain_detail.html:18 #: assets/templates/assets/domain_detail.html:18
@ -815,6 +706,15 @@ msgstr "资产列表"
msgid "Asset list of " msgid "Asset list of "
msgstr "资产列表" msgstr "资产列表"
#: assets/templates/assets/admin_user_assets.html:54
#: assets/templates/assets/admin_user_list.html:26
#: assets/templates/assets/asset_list.html:90
#: assets/templates/assets/system_user_asset.html:52
#: assets/templates/assets/system_user_list.html:30
#: users/templates/users/user_group_granted_asset.html:47
msgid "Reachable"
msgstr "可连接"
#: assets/templates/assets/admin_user_assets.html:66 #: assets/templates/assets/admin_user_assets.html:66
#: assets/templates/assets/system_user_asset.html:64 #: assets/templates/assets/system_user_asset.html:64
#: assets/templates/assets/system_user_detail.html:112 #: assets/templates/assets/system_user_detail.html:112
@ -834,6 +734,53 @@ msgstr "测试可连接性"
msgid "Test" msgid "Test"
msgstr "测试" msgstr "测试"
#: assets/templates/assets/admin_user_detail.html:24
#: assets/templates/assets/admin_user_list.html:85
#: assets/templates/assets/asset_detail.html:24
#: assets/templates/assets/asset_list.html:170
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:90
#: assets/templates/assets/domain_list.html:42
#: assets/templates/assets/label_list.html:38
#: assets/templates/assets/system_user_detail.html:26
#: assets/templates/assets/system_user_list.html:88
#: perms/templates/perms/asset_permission_detail.html:30
#: perms/templates/perms/asset_permission_list.html:191
#: terminal/templates/terminal/terminal_detail.html:16
#: terminal/templates/terminal/terminal_list.html:71
#: users/templates/users/user_detail.html:25
#: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_list.html:43
#: users/templates/users/user_list.html:76
#: users/templates/users/user_profile.html:135
#: users/templates/users/user_profile.html:143
msgid "Update"
msgstr "更新"
#: assets/templates/assets/admin_user_detail.html:28
#: assets/templates/assets/admin_user_list.html:86
#: assets/templates/assets/asset_detail.html:28
#: assets/templates/assets/asset_list.html:171
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:91
#: assets/templates/assets/domain_list.html:43
#: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:30
#: assets/templates/assets/system_user_list.html:89
#: ops/templates/ops/task_list.html:72
#: perms/templates/perms/asset_permission_detail.html:34
#: perms/templates/perms/asset_permission_list.html:192
#: terminal/templates/terminal/terminal_list.html:73
#: users/templates/users/user_detail.html:30
#: users/templates/users/user_group_detail.html:32
#: users/templates/users/user_group_list.html:45
#: users/templates/users/user_list.html:80
#: users/templates/users/user_list.html:84
msgid "Delete"
msgstr "删除"
#: assets/templates/assets/admin_user_detail.html:83 #: assets/templates/assets/admin_user_detail.html:83
msgid "Replace node assets admin user with this" msgid "Replace node assets admin user with this"
msgstr "替换资产的管理员" msgstr "替换资产的管理员"
@ -845,9 +792,9 @@ msgstr "选择节点"
#: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/admin_user_detail.html:100
#: assets/templates/assets/asset_detail.html:200 #: assets/templates/assets/asset_detail.html:200
#: assets/templates/assets/asset_list.html:603 #: assets/templates/assets/asset_list.html:600
#: assets/templates/assets/system_user_detail.html:183 #: assets/templates/assets/system_user_detail.html:183
#: assets/templates/assets/system_user_list.html:138 templates/_modal.html:16 #: assets/templates/assets/system_user_list.html:138 templates/_modal.html:22
#: terminal/templates/terminal/session_detail.html:108 #: terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:339 #: users/templates/users/user_detail.html:339
#: users/templates/users/user_detail.html:364 #: users/templates/users/user_detail.html:364
@ -876,7 +823,23 @@ msgstr "不可达"
msgid "Ratio" msgid "Ratio"
msgstr "比例" msgstr "比例"
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:197 #: assets/templates/assets/admin_user_list.html:30
#: assets/templates/assets/asset_list.html:91
#: assets/templates/assets/domain_gateway_list.html:62
#: assets/templates/assets/domain_list.html:18
#: assets/templates/assets/label_list.html:17
#: assets/templates/assets/system_user_list.html:34
#: 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:42
#: perms/templates/perms/asset_permission_list.html:60
#: terminal/templates/terminal/session_list.html:80
#: terminal/templates/terminal/terminal_list.html:36
#: users/templates/users/user_group_list.html:15
#: users/templates/users/user_list.html:28
msgid "Action"
msgstr "动作"
#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:198
msgid "Asset detail" msgid "Asset detail"
msgstr "资产详情" msgstr "资产详情"
@ -901,6 +864,23 @@ msgstr "创建日期"
msgid "Quick modify" msgid "Quick modify"
msgstr "快速修改" msgstr "快速修改"
#: assets/templates/assets/asset_detail.html:143
#: assets/templates/assets/asset_list.html:89
#: assets/templates/assets/user_asset_list.html:47 perms/models.py:25
#: perms/models.py:70
#: perms/templates/perms/asset_permission_create_update.html:47
#: perms/templates/perms/asset_permission_detail.html:120
#: perms/templates/perms/asset_permission_list.html:59
#: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/user_detail.html:128
#: users/templates/users/user_granted_asset.html:46
#: users/templates/users/user_group_granted_asset.html:46
#: users/templates/users/user_list.html:27
#: users/templates/users/user_profile.html:63
msgid "Active"
msgstr "激活中"
#: assets/templates/assets/asset_detail.html:160 #: assets/templates/assets/asset_detail.html:160
msgid "Refresh hardware" msgid "Refresh hardware"
msgstr "更新硬件信息" msgstr "更新硬件信息"
@ -914,8 +894,7 @@ msgstr "刷新"
msgid "Update successfully!" msgid "Update successfully!"
msgstr "更新成功" msgstr "更新成功"
#: assets/templates/assets/asset_list.html:63 #: assets/templates/assets/asset_list.html:63 assets/views/asset.py:97
#: assets/templates/assets/asset_list.html:120 assets/views/asset.py:96
msgid "Create asset" msgid "Create asset"
msgstr "创建资产" msgstr "创建资产"
@ -929,43 +908,75 @@ msgstr "导入"
msgid "Export" msgid "Export"
msgstr "导出" msgstr "导出"
#: assets/templates/assets/asset_list.html:88
msgid "Hardware"
msgstr "硬件"
#: assets/templates/assets/asset_list.html:100
#: users/templates/users/user_list.html:37
msgid "Delete selected"
msgstr "批量删除"
#: assets/templates/assets/asset_list.html:101
#: users/templates/users/user_list.html:38
msgid "Update selected"
msgstr "批量更新"
#: assets/templates/assets/asset_list.html:102 #: assets/templates/assets/asset_list.html:102
msgid "Remove from this node" msgid "Remove from this node"
msgstr "从节点移除" msgstr "从节点移除"
#: assets/templates/assets/asset_list.html:103
#: users/templates/users/user_list.html:39
msgid "Deactive selected"
msgstr "禁用所选"
#: assets/templates/assets/asset_list.html:104
#: users/templates/users/user_list.html:40
msgid "Active selected"
msgstr "激活所选"
#: assets/templates/assets/asset_list.html:121 #: assets/templates/assets/asset_list.html:121
msgid "Add asset"
msgstr "添加资产到节点"
#: assets/templates/assets/asset_list.html:122
msgid "Refresh node hardware info"
msgstr "更新节点资产硬件信息"
#: assets/templates/assets/asset_list.html:123
msgid "Test node connective"
msgstr "测试节点资产可连接性"
#: assets/templates/assets/asset_list.html:125
msgid "Add node" msgid "Add node"
msgstr "新建节点" msgstr "新建节点"
#: assets/templates/assets/asset_list.html:126 #: assets/templates/assets/asset_list.html:122
msgid "Rename node" msgid "Rename node"
msgstr "重命名节点" msgstr "重命名节点"
#: assets/templates/assets/asset_list.html:128 #: assets/templates/assets/asset_list.html:123
msgid "Delete node" msgid "Delete node"
msgstr "删除节点" msgstr "删除节点"
#: assets/templates/assets/asset_list.html:202 #: assets/templates/assets/asset_list.html:125
msgid "Add assets to node"
msgstr "添加资产到节点"
#: assets/templates/assets/asset_list.html:126
msgid "Move assets to node"
msgstr "移动资产到节点"
#: assets/templates/assets/asset_list.html:128
msgid "Refresh node hardware info"
msgstr "更新节点资产硬件信息"
#: assets/templates/assets/asset_list.html:129
msgid "Test node connective"
msgstr "测试节点资产可连接性"
#: assets/templates/assets/asset_list.html:204
msgid "Create node failed" msgid "Create node failed"
msgstr "创建节点失败" msgstr "创建节点失败"
#: assets/templates/assets/asset_list.html:215 #: assets/templates/assets/asset_list.html:216
msgid "Have child node, cancel" msgid "Have child node, cancel"
msgstr "存在子节点,不能删除" msgstr "存在子节点,不能删除"
#: assets/templates/assets/asset_list.html:598 #: assets/templates/assets/asset_list.html:218
msgid "Have assets, cancel"
msgstr "存在资产,不能删除"
#: assets/templates/assets/asset_list.html:595
#: assets/templates/assets/system_user_list.html:133 #: assets/templates/assets/system_user_list.html:133
#: users/templates/users/user_detail.html:334 #: users/templates/users/user_detail.html:334
#: users/templates/users/user_detail.html:359 #: users/templates/users/user_detail.html:359
@ -974,20 +985,20 @@ msgstr "存在子节点,不能删除"
msgid "Are you sure?" msgid "Are you sure?"
msgstr "你确认吗?" msgstr "你确认吗?"
#: assets/templates/assets/asset_list.html:599 #: assets/templates/assets/asset_list.html:596
msgid "This will delete the selected assets !!!" msgid "This will delete the selected assets !!!"
msgstr "删除选择资产" msgstr "删除选择资产"
#: assets/templates/assets/asset_list.html:607 #: assets/templates/assets/asset_list.html:604
msgid "Asset Deleted." msgid "Asset Deleted."
msgstr "已被删除" msgstr "已被删除"
#: assets/templates/assets/asset_list.html:608 #: assets/templates/assets/asset_list.html:605
#: assets/templates/assets/asset_list.html:613 #: assets/templates/assets/asset_list.html:610
msgid "Asset Delete" msgid "Asset Delete"
msgstr "删除" msgstr "删除"
#: assets/templates/assets/asset_list.html:612 #: assets/templates/assets/asset_list.html:609
msgid "Asset Deleting failed." msgid "Asset Deleting failed."
msgstr "删除失败" msgstr "删除失败"
@ -1108,23 +1119,19 @@ msgstr "更新管理用户"
msgid "Admin user detail" msgid "Admin user detail"
msgstr "管理用户详情" msgstr "管理用户详情"
#: assets/views/asset.py:50 templates/_nav.html:23 #: assets/views/asset.py:63 templates/_nav_user.html:4
msgid "Asset list"
msgstr "资产列表"
#: assets/views/asset.py:62 templates/_nav_user.html:4
msgid "My assets" msgid "My assets"
msgstr "我的资产" msgstr "我的资产"
#: assets/views/asset.py:156 #: assets/views/asset.py:157
msgid "Bulk update asset" msgid "Bulk update asset"
msgstr "批量更新资产" msgstr "批量更新资产"
#: assets/views/asset.py:173 #: assets/views/asset.py:174
msgid "Update asset" msgid "Update asset"
msgstr "更新资产" msgstr "更新资产"
#: assets/views/asset.py:308 #: assets/views/asset.py:311
msgid "already exists" msgid "already exists"
msgstr "已经存在" msgstr "已经存在"
@ -1906,7 +1913,7 @@ msgstr ""
"\"%(user_pubkey_update)s\"> 链接 </a> 更新\n" "\"%(user_pubkey_update)s\"> 链接 </a> 更新\n"
" " " "
#: templates/_modal.html:15 #: templates/_modal.html:21
msgid "Close" msgid "Close"
msgstr "关闭" msgstr "关闭"
@ -2449,11 +2456,6 @@ msgstr "重置密码"
msgid "Password again" msgid "Password again"
msgstr "再次输入密码" msgstr "再次输入密码"
#: users/templates/users/reset_password.html:57
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgstr "设置"
#: users/templates/users/user_create.html:4 #: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:16 users/views/user.py:75 #: users/templates/users/user_list.html:16 users/views/user.py:75
msgid "Create user" msgid "Create user"
@ -2839,3 +2841,5 @@ msgstr "密码更新"
msgid "Public key update" msgid "Public key update"
msgstr "密钥更新" msgstr "密钥更新"
#~ msgid "Add asset"
#~ msgstr "添加资产到节点"

View File

@ -36,9 +36,10 @@ urlpatterns = [
url(r'^captcha/', include('captcha.urls')), url(r'^captcha/', include('captcha.urls')),
] ]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \
+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
if settings.DEBUG: if settings.DEBUG:
urlpatterns += [ urlpatterns += [
url(r'^docs/', schema_view, name="docs"), url(r'^docs/', schema_view, name="docs"),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ ]
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -85,9 +85,9 @@
<form> <form>
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td colspan="2"> <td colspan="2">
<select data-placeholder="{% trans 'Select assets' %}" class="select2 asset" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select assets' %}" class="select2" id="asset_select2" style="width: 100%" multiple="" tabindex="4">
{% for asset in assets_remain %} {% for asset in assets_remain %}
<option value="{{ asset.id }}">{{ asset.hostname }}</option> <option value="{{ asset.id }}">{{ asset }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
@ -113,9 +113,9 @@
<form> <form>
<tr> <tr>
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Select nodes' %}" class="select2 group" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select nodes' %}" class="select2" id="node_select2" style="width: 100%" multiple="" tabindex="4">
{% for node in nodes_remain %} {% for node in nodes_remain %}
<option value="{{ node.id }}" id="opt_{{ node.id }}">{{ node.value }}</option> <option value="{{ node.id }}" id="opt_{{ node.id }}">{{ node }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
@ -129,9 +129,9 @@
{% for node in asset_permission.nodes.all %} {% for node in asset_permission.nodes.all %}
<tr> <tr>
<td ><b class="bdg_user_group" data-gid={{ node.id }}>{{ node.value }}</b></td> <td ><b class="bdg_group" data-gid={{ node.id }}>{{ node }}</b></td>
<td> <td>
<button class="btn btn-danger btn-xs btn-remove-node" type="button" style="float: right;"><i class="fa fa-minus"></i></button> <button class="btn btn-danger btn-xs btn-remove-node" type="button" data-gid="{{ node.id }}" style="float: right;"><i class="fa fa-minus"></i></button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -179,49 +179,30 @@ function removeAssets(assets) {
}); });
} }
function updateNodes(nodes) { function updateNodes(nodes, success) {
var the_url = "{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}"; var the_url = "{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}";
var body = { var body = {
nodes: nodes nodes: nodes
}; };
APIUpdateAttr({ APIUpdateAttr({
url: the_url, url: the_url,
body: JSON.stringify(body) body: JSON.stringify(body),
success: success
}); });
} }
jumpserver.assets_selected = {};
jumpserver.nodes_selected = {};
$(document).ready(function () { $(document).ready(function () {
$('.select2.asset').select2() $('.select2').select2();
.on('select2:select', function(evt) {
var data = evt.params.data;
jumpserver.assets_selected[data.id] = data.text;
})
.on('select2:unselect', function(evt) {
var data = evt.params.data;
delete jumpserver.assets_selected[data.id]
});
$('.select2.group').select2()
.on('select2:select', function(evt) {
var data = evt.params.data;
jumpserver.nodes_selected[data.id] = data.text;
})
.on('select2:unselect', function(evt) {
var data = evt.params.data;
delete jumpserver.nodes_selected[data.id]
})
}) })
.on('click', '.btn-add-assets', function () { .on('click', '.btn-add-assets', function () {
if (Object.keys(jumpserver.assets_selected).length === 0) { var assets_selected = $("#asset_select2 option:selected").map(function () {
return $(this).attr('value');
}).get();
if (assets_selected.length === 0) {
return false; return false;
} }
var assets = []; addAssets(assets_selected);
$.map(jumpserver.assets_selected, function(value, index) {
assets.push(index);
});
addAssets(assets);
}) })
.on('click', '.btn-remove-asset', function () { .on('click', '.btn-remove-asset', function () {
var asset_id = $(this).data("gid"); var asset_id = $(this).data("gid");
@ -232,26 +213,30 @@ $(document).ready(function () {
removeAssets(assets) removeAssets(assets)
}) })
.on('click', '#btn-add-node', function () { .on('click', '#btn-add-node', function () {
if (Object.keys(jumpserver.nodes_selected).length === 0) { var nodes_selected = {};
$("#node_select2 option:selected").each(function (i, data) {
nodes_selected[$(data).attr('value')] = $(data).text();
});
if (Object.keys(nodes_selected).length === 0) {
return false; return false;
} }
var nodes_origin = $('.bdg_group').map(function() {
var nodes = $('.bdg_group').map(function() {
return $(this).data('gid'); return $(this).data('gid');
}).get(); }).get();
$.map(jumpserver.nodes_selected, function(group_name, index) { var nodes = nodes_origin.concat(Object.keys(nodes_selected));
nodes.push(index); var success = function () {
$('#opt_' + index).remove(); $.map(nodes_selected, function(name, id) {
$('.group_edit tbody').append( $('#opt_' + id).remove();
'<tr>' + $('.group_edit tbody').append(
'<td><b class="bdg_group" data-gid="' + index + '">' + group_name + '</b></td>' + '<tr>' +
'<td><button class="btn btn-danger btn-xs pull-right btn-leave-group" type="button"><i class="fa fa-minus"></i></button></td>' + '<td><b class="bdg_group" data-gid="' + id + '">' + name + '</b></td>' +
'</tr>' '<td><button class="btn btn-danger btn-xs pull-right btn-leave-group" type="button"><i class="fa fa-minus"></i></button></td>' +
) '</tr>'
}); )
});
updateNodes(nodes); };
updateNodes(nodes, success);
}) })
.on('click', '.btn-remove-node', function () { .on('click', '.btn-remove-node', function () {
var $this = $(this); var $this = $(this);
@ -261,8 +246,10 @@ $(document).ready(function () {
return $(this).data('gid'); return $(this).data('gid');
} }
}).get(); }).get();
updateNodes(nodes); var success = function () {
$tr.remove() $tr.remove()
};
updateNodes(nodes, success);
}) })
</script> </script>
{% endblock %} {% endblock %}

View File

@ -76,20 +76,37 @@
</div> </div>
</div> </div>
</div> </div>
{% include 'assets/_asset_list_modal.html' %}
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script> <script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2(); $('.select2').select2({
$('#datepicker').datepicker({ closeOnSelect: false
format: "yyyy-mm-dd", });
todayBtn: "linked", $('#datepicker').datepicker({
keyboardNavigation: false, format: "yyyy-mm-dd",
forceParse: false, todayBtn: "linked",
calendarWeeks: true, keyboardNavigation: false,
autoclose: true forceParse: false,
}); calendarWeeks: true,
}) autoclose: true
</script> });
$("#id_assets").parent().find(".select2-selection").on('click', function (e) {
e.preventDefault();
$("#asset_list_modal").modal();
})
})
.on('click', '#btn_asset_modal_confirm', function () {
var assets = asset_table2.selected;
$('.select2 option:selected').each(function (i, data) {
assets.push($(data).attr('value'))
});
$.each(assets, function (id, data) {
$('.select2').val(assets).trigger('change');
});
$("#asset_list_modal").modal('hide');
})
</script>
{% endblock %} {% endblock %}

View File

@ -147,7 +147,7 @@
<td colspan="2"> <td colspan="2">
<select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for system_user in system_users_remain %} {% for system_user in system_users_remain %}
<option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user.name }}</option> <option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
@ -161,7 +161,7 @@
{% for system_user in object.system_users.all %} {% for system_user in object.system_users.all %}
<tr {% if forloop.counter == 1 %} class="no-borders-tr" {% endif %} > <tr {% if forloop.counter == 1 %} class="no-borders-tr" {% endif %} >
<td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user.name }}</b></td> <td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user }}</b></td>
<td> <td>
<button class="btn btn-danger btn-xs btn-remove-user" data-uid="{{ system_user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button> <button class="btn btn-danger btn-xs btn-remove-user" data-uid="{{ system_user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td> </td>

View File

@ -87,7 +87,7 @@
<td colspan="2"> <td colspan="2">
<select data-placeholder="{% trans 'Select user' %}" class="select2 user" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select user' %}" class="select2 user" style="width: 100%" multiple="" tabindex="4">
{% for user in users_remain %} {% for user in users_remain %}
<option value="{{ user.id }}">{{ user.name }}</option> <option value="{{ user.id }}">{{ user }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
@ -115,7 +115,7 @@
<td colspan="2" class="no-borders"> <td colspan="2" class="no-borders">
<select data-placeholder="{% trans 'Select user groups' %}" class="select2 user-group" style="width: 100%" multiple="" tabindex="4"> <select data-placeholder="{% trans 'Select user groups' %}" class="select2 user-group" style="width: 100%" multiple="" tabindex="4">
{% for user_group in user_groups_remain %} {% for user_group in user_groups_remain %}
<option value="{{ user_group.id }}" id="opt_{{ user_group.id }}">{{ user_group.name }}</option> <option value="{{ user_group.id }}" id="opt_{{ user_group.id }}">{{ user_group }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
@ -129,7 +129,7 @@
{% for user_group in asset_permission.user_groups.all %} {% for user_group in asset_permission.user_groups.all %}
<tr> <tr>
<td ><b class="bdg_group" data-gid={{ user_group.id }}>{{ user_group.name }}</b></td> <td ><b class="bdg_group" data-gid={{ user_group.id }}>{{ user_group }}</b></td>
<td> <td>
<button class="btn btn-danger btn-xs btn-remove-group" type="button" data-gid="{{ user_group.id }}" style="float: right;"><i class="fa fa-minus"></i></button> <button class="btn btn-danger btn-xs btn-remove-group" type="button" data-gid="{{ user_group.id }}" style="float: right;"><i class="fa fa-minus"></i></button>
</td> </td>

View File

@ -112,7 +112,7 @@ class AssetPermissionUserView(AdminUserRequiredMixin,
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
queryset = self.object.get_all_users() queryset = list(self.object.get_all_users())
return queryset return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -142,7 +142,7 @@ class AssetPermissionAssetView(AdminUserRequiredMixin,
return super().get(request, *args, **kwargs) return super().get(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
queryset = self.object.get_all_assets() queryset = list(self.object.get_all_assets())
return queryset return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):

View File

@ -307,7 +307,7 @@ jumpserver.initDataTable = function (options) {
last: "»" last: "»"
} }
}, },
lengthMenu: [[15, 25, 50, -1], [15, 25, 50, "All"]] lengthMenu: [[10, 15, 25, 50, -1], [10, 15, 25, 50, "All"]]
}); });
table.on('select', function(e, dt, type, indexes) { table.on('select', function(e, dt, type, indexes) {
var $node = table[ type ]( indexes ).nodes().to$(); var $node = table[ type ]( indexes ).nodes().to$();
@ -446,22 +446,56 @@ jumpserver.initServerSideDataTable = function (options) {
last: "»" last: "»"
} }
}, },
lengthMenu: [[15, 25, 50], [15, 25, 50]] lengthMenu: [[10, 15, 25, 50], [10, 15, 25, 50]]
}); });
table.selected = [];
table.on('select', function(e, dt, type, indexes) { table.on('select', function(e, dt, type, indexes) {
var $node = table[ type ]( indexes ).nodes().to$(); var $node = table[ type ]( indexes ).nodes().to$();
$node.find('input.ipt_check').prop('checked', true); $node.find('input.ipt_check').prop('checked', true);
jumpserver.selected[$node.find('input.ipt_check').prop('id')] = true jumpserver.selected[$node.find('input.ipt_check').prop('id')] = true;
if (type === 'row') {
var rows = table.rows(indexes).data();
$.each(rows, function (id, row) {
if (row.id){
table.selected.push(row.id)
}
})
}
}).on('deselect', function(e, dt, type, indexes) { }).on('deselect', function(e, dt, type, indexes) {
var $node = table[ type ]( indexes ).nodes().to$(); var $node = table[ type ]( indexes ).nodes().to$();
$node.find('input.ipt_check').prop('checked', false); $node.find('input.ipt_check').prop('checked', false);
jumpserver.selected[$node.find('input.ipt_check').prop('id')] = false jumpserver.selected[$node.find('input.ipt_check').prop('id')] = false;
if (type === 'row') {
var rows = table.rows(indexes).data();
$.each(rows, function (id, row) {
if (row.id){
var index = table.selected.indexOf(row.id);
if (index > -1){
table.selected.splice(index, 1)
}
}
})
}
}). }).
on('draw', function(){ on('draw', function(){
$('#op').html(options.op_html || ''); $('#op').html(options.op_html || '');
$('#uc').html(options.uc_html || ''); $('#uc').html(options.uc_html || '');
var table_data = [];
$.each(table.rows().data(), function (id, row) {
if (row.id) {
table_data.push(row.id)
}
});
$.each(table.selected, function (id, data) {
var index = table_data.indexOf(data);
if (index > -1){
table.rows(index).select()
}
});
}); });
$('.ipt_check_all').on('click', function() { var table_id = table.settings()[0].sTableId;
$('#' + table_id + ' .ipt_check_all').on('click', function() {
if ($(this).prop("checked")) { if ($(this).prop("checked")) {
$(this).closest('table').find('.ipt_check').prop('checked', true); $(this).closest('table').find('.ipt_check').prop('checked', true);
table.rows({search:'applied', page:'current'}).select(); table.rows({search:'applied', page:'current'}).select();

View File

@ -1,4 +1,9 @@
{% load i18n %} {% load i18n %}
<style>
.modal-body {
padding: 0px 20px 0px 20px;
}
</style>
<div aria-hidden="true" role="dialog" id="{% block modal_id %}{% endblock %}" class="modal inmodal"> <div aria-hidden="true" role="dialog" id="{% block modal_id %}{% endblock %}" class="modal inmodal">
<div class="modal-dialog {% block modal_class %}{% endblock %}"> <div class="modal-dialog {% block modal_class %}{% endblock %}">
<div class="modal-content animated fadeIn"> <div class="modal-content animated fadeIn">
@ -12,8 +17,10 @@
{% endblock %} {% endblock %}
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
{% block modal_button %}
<button data-dismiss="modal" class="btn btn-white" type="button">{% trans "Close" %}</button> <button data-dismiss="modal" class="btn btn-white" type="button">{% trans "Close" %}</button>
<button class="btn btn-primary" type="button" id="{% block modal_confirm_id %}{% endblock %}">{% trans 'Confirm' %}</button> <button class="btn btn-primary" type="button" id="{% block modal_confirm_id %}{% endblock %}">{% trans 'Confirm' %}</button>
{% endblock %}
</div> </div>
</div> </div>
</div> </div>

View File

@ -61,7 +61,7 @@
</li> </li>
<li id="audits"> <li id="audits">
<a> <a>
<i class="fa fa-coffee" style="width: 14px"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span> <i class="fa fa-history" style="width: 14px"></i> <span class="nav-label">{% trans 'Audits' %}</span><span class="fa arrow"></span>
</a> </a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li id="ftp-log"><a href="{% url 'audits:ftp-log-list' %}">{% trans 'FTP log' %}</a></li> <li id="ftp-log"><a href="{% url 'audits:ftp-log-list' %}">{% trans 'FTP log' %}</a></li>

View File

@ -248,7 +248,7 @@ class CommandViewSet(viewsets.ViewSet):
class SessionReplayViewSet(viewsets.ViewSet): class SessionReplayViewSet(viewsets.ViewSet):
serializer_class = ReplaySerializer serializer_class = ReplaySerializer
permission_classes = () permission_classes = (IsSuperUserOrAppUser,)
session = None session = None
def gen_session_path(self): def gen_session_path(self):

View File

@ -45,7 +45,7 @@ class User(AbstractUser):
wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat')) wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat'))
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone')) phone = models.CharField(max_length=20, blank=True, null=True, verbose_name=_('Phone'))
otp_level = models.SmallIntegerField(default=0, choices=OTP_LEVEL_CHOICES, verbose_name=_('Enable OTP')) otp_level = models.SmallIntegerField(default=0, choices=OTP_LEVEL_CHOICES, verbose_name=_('Enable OTP'))
otp_secret_key = models.CharField(max_length=16, blank=True, null=True) _otp_secret_key = models.CharField(max_length=128, blank=True, null=True)
# Todo: Auto generate key, let user download # Todo: Auto generate key, let user download
_private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Private key')) _private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Private key'))
_public_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Public key')) _public_key = models.CharField(max_length=5000, blank=True, verbose_name=_('Public key'))
@ -70,6 +70,14 @@ class User(AbstractUser):
def password_raw(self, password_raw_): def password_raw(self, password_raw_):
self.set_password(password_raw_) self.set_password(password_raw_)
@property
def otp_secret_key(self):
return signer.unsign(self._otp_secret_key)
@otp_secret_key.setter
def otp_secret_key(self, item):
self._otp_secret_key = signer.sign(item).decode('utf-8')
def get_absolute_url(self): def get_absolute_url(self):
return reverse('users:user-detail', args=(self.id,)) return reverse('users:user-detail', args=(self.id,))