diff --git a/apps/__init__.py b/apps/__init__.py index 6110e1346664e7d5b434744d71763880787d1973..7f7347e2eeec82d7d00e2cb67b3439650ca2b8a9 100644 --- a/apps/__init__.py +++ b/apps/__init__.py @@ -2,4 +2,4 @@ # -*- coding: utf-8 -*- # -__version__ = "1.0.0" +__version__ = "1.2.0" diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index d7499760a909cb1c28b4707697d63d4c2180f2ed..f123e4649af5e05080209a5ad8a7814fbe4d5744 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -32,6 +32,7 @@ __all__ = [ 'NodeViewSet', 'NodeChildrenApi', 'NodeAssetsApi', 'NodeWithAssetsApi', 'NodeAddAssetsApi', 'NodeRemoveAssetsApi', + 'NodeReplaceAssetsApi', 'NodeAddChildrenApi', 'RefreshNodeHardwareInfoApi', 'TestNodeConnectiveApi' ] @@ -191,6 +192,19 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView): 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): permission_classes = (IsSuperUser,) model = Node diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py index 1f42a297878ec6a9e286983ae829cf96e920416b..5b3009305faf411ca8613f45178053b829eabc04 100644 --- a/apps/assets/models/asset.py +++ b/apps/assets/models/asset.py @@ -49,6 +49,7 @@ class Asset(models.Model): ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True) hostname = models.CharField(max_length=128, unique=True, verbose_name=_('Hostname')) 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) nodes = models.ManyToManyField('assets.Node', default=default_node, related_name='assets', verbose_name=_("Nodes")) 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_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_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')) @@ -84,7 +84,7 @@ class Asset(models.Model): comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) def __str__(self): - return self.hostname + return '{0.hostname}({0.ip})'.format(self) @property def is_valid(self): diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 99236f781a2ce6ca6b84dba9e76b60bbdfe964fc..ad806342be49c7fcc96b8ca994b8c61b10709206 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -19,7 +19,7 @@ class Node(models.Model): is_asset = False def __str__(self): - return self.value + return self.full_value @property def name(self): @@ -30,7 +30,7 @@ class Node(models.Model): if self == self.__class__.root(): return self.value else: - return '{}/{}'.format(self.value, self.parent.full_value) + return '{} / {}'.format(self.parent.full_value, self.value) @property def level(self): @@ -72,7 +72,7 @@ class Node(models.Model): assets = Asset.objects.all() else: nodes = self.get_family() - assets = Asset.objects.filter(nodes__in=nodes) + assets = Asset.objects.filter(nodes__in=nodes).distinct() return assets def has_assets(self): diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index e0de2cf49825bb162175d84e925a0480b29d9ae1..bf31b8491c5a14bf7841584700c71a37117025eb 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -109,7 +109,7 @@ class SystemUser(AssetUser): shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell')) def __str__(self): - return self.name + return '{0.name}({0.username})'.format(self) def to_json(self): return { diff --git a/apps/assets/tasks.py b/apps/assets/tasks.py index 381e1a4cff8bdd769172af55eb6176df0e9742c7..dd660bc4296b0f6bb50c6455a0827068219ee2e0 100644 --- a/apps/assets/tasks.py +++ b/apps/assets/tasks.py @@ -96,6 +96,9 @@ def update_assets_hardware_info_util(assets, task_name=None): task_name = _("更新资产硬件信æ¯") tasks = const.UPDATE_ASSETS_HARDWARE_TASKS 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_name, hosts=hostname_list, tasks=tasks, pattern='all', options=const.TASK_OPTIONS, run_as_admin=True, created_by='System', diff --git a/apps/assets/templates/assets/_asset_list_modal.html b/apps/assets/templates/assets/_asset_list_modal.html index b68ab0378aec235c3c73ae740372a12c754d90eb..c5cd48857ba4f98ec1c1d4fd864cfc047e677157 100644 --- a/apps/assets/templates/assets/_asset_list_modal.html +++ b/apps/assets/templates/assets/_asset_list_modal.html @@ -1,132 +1,125 @@ {% extends '_modal.html' %} {% load i18n %} +{% load static %} {% block modal_class %}modal-lg{% 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 %} -{#<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>#} -<table class="table table-striped table-bordered table-hover " id="asset_modal_table" width="100%"> - <thead> - <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> - <th class="text-center">{% trans 'Hardware' %}</th> - <th class="text-center">{% trans 'Active' %}</th> - <th class="text-center">{% trans 'Reachable' %}</th> - <th class="text-center">{% trans 'Action' %}</th> - </tr> - </thead> - <tbody> - </tbody> -</table> -<div id="actions" class="hide"> - <div class="input-group"> - <select class="form-control m-b" style="width: auto" id="slct_bulk_update"> - <option value="delete">{% trans 'Delete selected' %}</option> - <option value="update">{% trans 'Update selected' %}</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> +<link href="{% static 'css/plugins/ztree/awesomeStyle/awesome.css' %}" rel="stylesheet"> +<script type="text/javascript" src="{% static 'js/plugins/ztree/jquery.ztree.all.min.js' %}"></script> +<script src="{% static 'js/jquery.form.min.js' %}"></script> +<style> +.inmodal .modal-header { + padding: 10px 10px; + text-align: center; +} + +#assetTree2.ztree * { + background-color: #f8fafb; +} +#assetTree2.ztree { + background-color: #f8fafb; +} +</style> + +<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="assetTree2" class="ztree"> + </div> + <div class="clearfix"></div> + </div> + </div> + </div> + </div> + <div class="col-lg-9 animated fadeInRight" id="split-right"> + <div class="mail-box-header"> + <table class="table table-striped table-bordered table-hover " id="asset_list_modal_table" style="width: 100%"> + <thead> + <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> -<script> - -var modal_table; -function initModalTable() { +<script> +var zTree2, asset_table2 = 0; +function initTable2() { var options = { - ele: $('#asset_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) - }} - ], + ele: $('#asset_list_modal_table'), ajax_url: '{% url "api-assets:asset-list" %}', columns: [ - {data: "id"}, {data: "hostname" }, {data: "ip" }, - {data: "cpu_cores"}, {data: "is_active", orderable: false }, - {data: "is_connective", orderable: false}, {data: "id", orderable: false } + {data: "id"}, {data: "hostname" }, {data: "ip" } ], - op_html: $('#actions').html() + pageLength: 10 }; - modal_table = jumpserver.initServerSideDataTable(options); - return modal_table; + asset_table2 = jumpserver.initServerSideDataTable(options); + return asset_table2 } -$(document).ready(function(){ - initModalTable(); -}).on('click', '#btn_select_assets', function () { - var data_table = $('#asset_modal_table').DataTable(); - var id_list = []; - data_table.rows({selected: true}).every(function(){ - id_list.push(this.data().id); - }); - var current_node; - var nodes = zTree.getSelectedNodes(); - if (nodes && nodes.length === 1) { - current_node = nodes[0] - } else { - return - } +function onSelected2(event, treeNode) { + var url = asset_table2.ajax.url(); + url = setUrlParam(url, "node_id", treeNode.id); + setCookie('node_selected', treeNode.id); + asset_table2.ajax.url(url); + asset_table2.ajax.reload(); +} - var data = { - 'assets': id_list - }; - var success = function () { - modal_table.ajax.reload() +function initTree2() { + var setting = { + view: { + dblClickExpand: false, + showLine: true + }, + data: { + simpleData: { + enable: true + } + }, + callback: { + onSelected: onSelected2 + } }; - APIUpdateAttr({ - 'url': '/api/assets/v1/nodes/' + current_node.id + '/assets/add/', - 'method': 'PUT', - 'body': JSON.stringify(data), - 'success': success - }) + 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"); + }); +} + + +$(document).ready(function(){ + initTable2(); + initTree2(); }) </script> +{% endblock %} +{% block modal_button %} + {{ block.super }} {% endblock %} -{% block modal_confirm_id %}btn_select_assets{% endblock %} +{% block modal_confirm_id %}btn_asset_modal_confirm{% endblock %} + diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html index fd57d96437eff04351bf59dafe31dd1a34701943..0b1b2865a4b624d28521a3c663153e09294f7844 100644 --- a/apps/assets/templates/assets/asset_detail.html +++ b/apps/assets/templates/assets/asset_detail.html @@ -305,9 +305,9 @@ $(document).ready(function () { success_message: success }); 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{ - $(".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 () { if (Object.keys(jumpserver.nodes_selected).length === 0) { diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index 18dc31645e85dc5cb24c256ec8a8ca775048a1ea..04ba11e573b036fb449c7951d70f7789dc4b046a 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -59,57 +59,57 @@ <i class="fa fa-angle-left fa-x" id="toggle-icon"></i> </div> </div> - <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="html5buttons"> - <div class="dt-buttons btn-group"> - <a class="btn btn-default btn_import" data-toggle="modal" data-target="#asset_import_modal" tabindex="0"> - <span>{% trans "Import" %}</span> - </a> - <a class="btn btn-default btn_export" tabindex="0"> - <span>{% trans "Export" %}</span> - </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 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="html5buttons"> + <div class="dt-buttons btn-group"> + <a class="btn btn-default btn_import" data-toggle="modal" data-target="#asset_import_modal" tabindex="0"> + <span>{% trans "Import" %}</span> + </a> + <a class="btn btn-default btn_export" tabindex="0"> + <span>{% trans "Export" %}</span> + </a> </div> - <table class="table table-striped table-bordered table-hover " id="asset_list_table" style="width: 100%"> - <thead> - <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> - <th class="text-center">{% trans 'Hardware' %}</th> - <th class="text-center">{% trans 'Active' %}</th> - <th class="text-center">{% trans 'Reachable' %}</th> - <th class="text-center">{% trans 'Action' %}</th> - </tr> - </thead> - <tbody> - </tbody> - </table> - <div id="actions" class="hide"> - <div class="input-group"> - <select class="form-control m-b" style="width: auto" id="slct_bulk_update"> - <option value="delete">{% trans 'Delete selected' %}</option> - <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 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> + <table class="table table-striped table-bordered table-hover " id="asset_list_table" style="width: 100%"> + <thead> + <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> + <th class="text-center">{% trans 'Hardware' %}</th> + <th class="text-center">{% trans 'Active' %}</th> + <th class="text-center">{% trans 'Reachable' %}</th> + <th class="text-center">{% trans 'Action' %}</th> + </tr> + </thead> + <tbody> + </tbody> + </table> + <div id="actions" class="hide"> + <div class="input-group"> + <select class="form-control m-b" style="width: auto" id="slct_bulk_update"> + <option value="delete">{% trans 'Delete selected' %}</option> + <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> @@ -117,15 +117,16 @@ <div id="rMenu"> <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 id="m_create" tabindex="-1" onclick="addTreeNode();"><a>{% trans 'Add node' %}</a></li> - <li id="m_del" tabindex="-1" onclick="editTreeNode();"><a>{% trans 'Rename 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><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="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> </div> @@ -136,6 +137,7 @@ {% block custom_foot_js %} <script> var zTree, rMenu, asset_table, show = 0; +var update_node_action = ""; function initTable() { var options = { ele: $('#asset_list_table'), @@ -210,10 +212,11 @@ function removeTreeNode() { if (!current_node){ return } - if (current_node.children && current_node.children.length > 0) { - alert("{% trans 'Have child node, cancel' %}") - } else { + toastr.error("{% trans 'Have child node, cancel' %}"); + } 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 ); $.ajax({ url: url, @@ -249,13 +252,6 @@ function OnRightClick(event, treeId, treeNode) { function showRMenu(type, x, y) { $("#rMenu ul").show(); - {#if (type === "root") {#} - {# return#} - {# } else {#} - {# $("#m_del").show();#} - {# $("#m_check").show();#} - {# $("#m_unCheck").show();#} - {# }#} x -= 220; rMenu.css({"top":y+"px", "left":x+"px", "visibility":"visible"}); @@ -459,7 +455,8 @@ $(document).ready(function(){ var current_node; if (nodes && nodes.length ===1 ){ 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.find('.help-block').remove(); @@ -673,7 +670,45 @@ $(document).ready(function(){ break; } $(".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> {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/domain_create_update.html b/apps/assets/templates/assets/domain_create_update.html index 36ca40fc11bbc24050f7239a0a488e7628f4069a..3ad8724e9eac9d7a11a1fc661cf31f98d2f35e0a 100644 --- a/apps/assets/templates/assets/domain_create_update.html +++ b/apps/assets/templates/assets/domain_create_update.html @@ -18,14 +18,25 @@ </div> </div> </form> +{% include 'assets/_asset_list_modal.html' %} {% endblock %} {% block custom_foot_js %} <script type="text/javascript"> - $(document).ready(function () { - $('.select2').select2({ - closeOnSelect: false - }); +$(document).ready(function () { + console.log($.fn.select2.defaults); + $('.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> {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/domain_gateway_list.html b/apps/assets/templates/assets/domain_gateway_list.html index 3dc82652f3cb0af1b00726b5548cee7abb8285a3..581f6c08ae679623b9ae602e47d8e7de8a9a6455 100644 --- a/apps/assets/templates/assets/domain_gateway_list.html +++ b/apps/assets/templates/assets/domain_gateway_list.html @@ -81,11 +81,6 @@ function initTable() { var options = { ele: $('#domain_list_table'), 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) { 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); diff --git a/apps/assets/templates/assets/label_create_update.html b/apps/assets/templates/assets/label_create_update.html index 358faaab882b337673e5ad1fd296841d803d474e..b26ec64643387fb178b2defaf5235204a44a3014 100644 --- a/apps/assets/templates/assets/label_create_update.html +++ b/apps/assets/templates/assets/label_create_update.html @@ -3,6 +3,8 @@ {% load bootstrap3 %} {% load i18n %} + + {% block form %} <form id="groupForm" method="post" class="form-horizontal"> {% csrf_token %} @@ -18,14 +20,28 @@ </div> </div> </form> +{% include 'assets/_asset_list_modal.html' %} {% endblock %} {% block custom_foot_js %} <script type="text/javascript"> - $(document).ready(function () { - $('.select2').select2({ - closeOnSelect: false - }); +$(document).ready(function () { + $('.select2').select2({ + 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> {% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index 3572cfd3d18e75f7ed70c47306ebf6f3d84ee3f7..a02bf1e44e5d203a27cbff89ee4ff7f03007a998 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -173,7 +173,7 @@ <td colspan="2" class="no-borders"> <select data-placeholder="{% trans 'Add to node' %}" id="node_selected" class="select2" style="width: 100%" multiple="" tabindex="4"> {% 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 %} </select> </td> @@ -187,7 +187,7 @@ {% for node in system_user.nodes.all %} <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> <button class="btn btn-danger pull-right btn-xs btn-remove-from-node" type="button"><i class="fa fa-minus"></i></button> </td> diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index c4925059a0eaac87f534af0ff558a9121001f7d8..4429d0f24ff8f86c85d4cfb7091b77532ae5afde 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -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})/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/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})/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'), diff --git a/apps/assets/views/asset.py b/apps/assets/views/asset.py index 953f3c8acb55ac7e8d90272e14ba9cc6020df7be..306a26a0aa3e11c1faccc74f7f61ab3ae2eec3ff 100644 --- a/apps/assets/views/asset.py +++ b/apps/assets/views/asset.py @@ -49,6 +49,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView): 'app': _('Assets'), 'action': _('Asset list'), 'labels': Label.objects.all().order_by('name'), + 'nodes': Node.objects.all().order_by('-key'), } kwargs.update(context) return super().get_context_data(**kwargs) @@ -284,24 +285,26 @@ class BulkImportAssetView(AdminUserRequiredMixin, JSONResponseMixin, FormView): if set(row) == {''}: continue - asset_dict = dict(zip(attr, row)) - id_ = asset_dict.pop('id', 0) - for k, v in asset_dict.items(): + asset_dict_raw = dict(zip(attr, row)) + asset_dict = dict() + for k, v in asset_dict_raw.items(): v = v.strip() 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': v = get_object_or_none(AdminUser, name=v) elif k in ['port', 'cpu_count', 'cpu_cores']: try: v = int(v) except ValueError: - v = 0 + v = '' elif k == 'domain': 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: try: 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))) else: for k, v in asset_dict.items(): - if v: + if v != '': setattr(asset, k, v) try: asset.save() diff --git a/apps/common/fields.py b/apps/common/fields.py index a06106cfaf29cb710264abbecd85b4d499773cb7..355344cd961b50033ef9eeb88eb475420424377e 100644 --- a/apps/common/fields.py +++ b/apps/common/fields.py @@ -2,11 +2,15 @@ # import json +from django.db import models from django import forms from django.utils import six from django.core.exceptions import ValidationError from django.utils.translation import ugettext as _ from rest_framework import serializers +from .utils import get_signer + +signer = get_signer() class DictField(forms.Field): @@ -46,4 +50,27 @@ class StringIDField(serializers.Field): class StringManyToManyField(serializers.RelatedField): def to_representation(self, value): - return value.__str__() \ No newline at end of file + 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) + diff --git a/apps/i18n/zh/LC_MESSAGES/django.mo b/apps/i18n/zh/LC_MESSAGES/django.mo index 61ef6ec21bb6059e9edbfaf75676af11deac619e..a343d985af7dfd3579a03d47852c15e6b2e7ed68 100644 Binary files a/apps/i18n/zh/LC_MESSAGES/django.mo and b/apps/i18n/zh/LC_MESSAGES/django.mo differ diff --git a/apps/i18n/zh/LC_MESSAGES/django.po b/apps/i18n/zh/LC_MESSAGES/django.po index fc8255313d0d747c78587655069df6dd2ce11b7a..5c559f24e3b3dedcdfd6ce6ee5743df5f8d1c99c 100644 --- a/apps/i18n/zh/LC_MESSAGES/django.po +++ b/apps/i18n/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-04-06 10:24+0800\n" +"POT-Creation-Date: 2018-04-13 17:27+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" @@ -17,45 +17,57 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: assets/api/node.py:58 +#: assets/api/node.py:88 msgid "New node {}" msgstr "新节点 {}" -#: assets/api/node.py:133 +#: assets/api/node.py:216 msgid "更新节点资产硬件信æ¯: {}" msgstr "" -#: assets/api/node.py:146 +#: assets/api/node.py:229 msgid "测试节点下资产是å¦å¯è¿žæŽ¥: {}" msgstr "" -#: assets/forms/asset.py:24 assets/forms/asset.py:60 assets/models/asset.py:53 -#: assets/models/user.py:102 assets/templates/assets/asset_detail.html:183 +#: 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:191 -#: assets/templates/assets/system_user_detail.html:166 +#: assets/templates/assets/system_user_detail.html:166 perms/models.py:23 msgid "Nodes" msgstr "节点管ç†" -#: assets/forms/asset.py:27 assets/forms/asset.py:63 assets/forms/asset.py:103 -#: assets/forms/asset.py:107 assets/models/asset.py:57 -#: assets/models/cluster.py:19 assets/models/user.py:71 +#: assets/forms/asset.py:27 assets/forms/asset.py:66 assets/forms/asset.py:109 +#: assets/forms/asset.py:113 assets/models/asset.py:58 +#: assets/models/cluster.py:19 assets/models/user.py:72 #: assets/templates/assets/asset_detail.html:73 templates/_nav.html:25 msgid "Admin user" msgstr "管ç†ç”¨æˆ·" -#: assets/forms/asset.py:30 assets/forms/asset.py:66 assets/models/asset.py:81 -#: assets/templates/assets/asset_create.html:33 -#: assets/templates/assets/asset_detail.html:220 -#: assets/templates/assets/asset_update.html:38 templates/_nav.html:27 -msgid "Labels" -msgstr "æ ‡ç¾ç®¡ç†" +#: assets/forms/asset.py:30 assets/forms/asset.py:69 assets/forms/asset.py:125 +#: assets/templates/assets/asset_create.html:35 +#: assets/templates/assets/asset_create.html:37 +#: assets/templates/assets/asset_list.html:75 +#: assets/templates/assets/asset_update.html:40 +#: assets/templates/assets/asset_update.html:42 +#: assets/templates/assets/user_asset_list.html:34 +msgid "Label" +msgstr "æ ‡ç¾" -#: assets/forms/asset.py:34 assets/forms/asset.py:70 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 msgid "Domain" msgstr "网域" -#: assets/forms/asset.py:42 assets/forms/asset.py:79 +#: assets/forms/asset.py:38 assets/forms/asset.py:63 assets/forms/asset.py:77 +#: assets/forms/asset.py:128 assets/templates/assets/asset_create.html:29 +#: assets/templates/assets/asset_update.html:34 perms/forms.py:40 +#: perms/forms.py:47 perms/models.py:67 +#: perms/templates/perms/asset_permission_list.html:57 +#: perms/templates/perms/asset_permission_list.html:142 +msgid "Node" +msgstr "节点" + +#: assets/forms/asset.py:45 assets/forms/asset.py:85 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" @@ -63,46 +75,41 @@ msgstr "" "root或其他拥有NOPASSWD: ALLæƒé™çš„用户, 如果是windows或其它硬件å¯ä»¥éšæ„设置一" "个, æ›´å¤šä¿¡æ¯æŸ¥çœ‹å·¦ä¾§ `管ç†ç”¨æˆ·` èœå•" -#: assets/forms/asset.py:45 assets/forms/asset.py:82 +#: assets/forms/asset.py:48 assets/forms/asset.py:88 msgid "* required Must set exact system platform, Windows, Linux ..." msgstr "* required 必须准确设置æ“作系统平å°ï¼Œå¦‚Windows, Linux ..." -#: assets/forms/asset.py:46 assets/forms/asset.py:83 +#: assets/forms/asset.py:49 assets/forms/asset.py:89 msgid "" "If your have some network not connect with each other, you can set domain" msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,使用网域网关跳转登录" -#: assets/forms/asset.py:90 assets/forms/asset.py:94 assets/forms/domain.py:16 +#: assets/forms/asset.py:96 assets/forms/asset.py:100 assets/forms/domain.py:16 #: assets/forms/label.py:15 -#: perms/templates/perms/asset_permission_asset.html:88 users/forms.py:272 +#: perms/templates/perms/asset_permission_asset.html:88 msgid "Select assets" msgstr "选择资产" -#: assets/forms/asset.py:99 assets/models/asset.py:51 +#: assets/forms/asset.py:105 assets/models/asset.py:51 #: assets/models/domain.py:44 assets/templates/assets/admin_user_assets.html:53 #: assets/templates/assets/asset_detail.html:69 #: assets/templates/assets/domain_gateway_list.html:58 #: assets/templates/assets/system_user_asset.html:51 -#: assets/templates/assets/user_asset_list.html:21 msgid "Port" msgstr "端å£" -#: assets/forms/asset.py:119 assets/templates/assets/asset_create.html:37 -msgid "Select labels" -msgstr "é€‰æ‹©æ ‡ç¾" - -#: assets/forms/asset.py:122 assets/templates/assets/admin_user_detail.html:91 -msgid "Select nodes" -msgstr "选择节点" - #: assets/forms/domain.py:14 assets/forms/label.py:13 -#: assets/models/asset.py:165 assets/templates/assets/admin_user_list.html:25 +#: assets/models/asset.py:169 assets/templates/assets/admin_user_list.html:25 #: assets/templates/assets/domain_detail.html:60 #: assets/templates/assets/domain_list.html:15 #: assets/templates/assets/label_list.html:16 #: assets/templates/assets/system_user_list.html:29 audits/models.py:11 #: audits/templates/audits/ftp_log_list.html:41 -#: audits/templates/audits/ftp_log_list.html:72 perms/models.py:17 +#: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:37 +#: perms/models.py:22 +#: perms/templates/perms/asset_permission_create_update.html:40 +#: perms/templates/perms/asset_permission_list.html:56 +#: perms/templates/perms/asset_permission_list.html:139 #: terminal/backends/command/models.py:11 terminal/models.py:123 #: terminal/templates/terminal/command_list.html:40 #: terminal/templates/terminal/command_list.html:73 @@ -125,11 +132,12 @@ msgstr "资产" #: common/templates/common/terminal_setting.html:67 #: common/templates/common/terminal_setting.html:85 ops/models/adhoc.py:36 #: ops/templates/ops/task_detail.html:59 ops/templates/ops/task_list.html:35 -#: perms/models.py:14 perms/templates/perms/asset_permission_detail.html:62 +#: perms/models.py:19 perms/templates/perms/asset_permission_detail.html:62 +#: perms/templates/perms/asset_permission_list.html:53 #: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:16 #: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 -#: users/models/user.py:35 users/templates/users/_select_user_modal.html:13 +#: users/models/user.py:40 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:12 @@ -145,8 +153,8 @@ msgstr "åç§°" #: assets/templates/assets/domain_gateway_list.html:60 #: assets/templates/assets/system_user_detail.html:62 #: assets/templates/assets/system_user_list.html:27 -#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:14 -#: users/models/authentication.py:45 users/models/user.py:34 +#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:13 +#: users/models/authentication.py:45 users/models/user.py:39 #: users/templates/users/_select_user_modal.html:14 #: users/templates/users/login.html:56 #: users/templates/users/login_log_list.html:49 @@ -161,7 +169,7 @@ msgid "Password or private key passphrase" msgstr "å¯†ç æˆ–密钥密ç " #: assets/forms/user.py:25 assets/models/base.py:22 common/forms.py:113 -#: users/forms.py:16 users/forms.py:25 users/templates/users/login.html:59 +#: users/forms.py:15 users/forms.py:24 users/templates/users/login.html:59 #: users/templates/users/reset_password.html:52 #: users/templates/users/user_create.html:11 #: users/templates/users/user_password_update.html:40 @@ -170,7 +178,7 @@ msgstr "å¯†ç æˆ–密钥密ç " msgid "Password" msgstr "密ç " -#: assets/forms/user.py:28 users/models/user.py:45 +#: assets/forms/user.py:28 users/models/user.py:50 msgid "Private key" msgstr "sshç§é’¥" @@ -193,13 +201,13 @@ msgid "" msgstr "高优先级的系统用户将会作为默认登录用户" #: 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/asset_detail.html:61 #: assets/templates/assets/asset_list.html:87 #: assets/templates/assets/domain_gateway_list.html:57 #: assets/templates/assets/system_user_asset.html:50 -#: assets/templates/assets/user_asset_list.html:20 common/forms.py:144 +#: assets/templates/assets/user_asset_list.html:46 common/forms.py:144 #: perms/templates/perms/asset_permission_asset.html:55 #: users/templates/users/login_log_list.html:52 #: users/templates/users/user_granted_asset.html:45 @@ -207,72 +215,71 @@ msgstr "高优先级的系统用户将会作为默认登录用户" msgid "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/asset_detail.html:57 #: assets/templates/assets/asset_list.html:86 #: assets/templates/assets/system_user_asset.html:49 -#: assets/templates/assets/user_asset_list.html:19 common/forms.py:143 +#: assets/templates/assets/user_asset_list.html:45 common/forms.py:143 #: perms/templates/perms/asset_permission_asset.html:54 #: users/templates/users/user_granted_asset.html:44 #: users/templates/users/user_group_granted_asset.html:44 msgid "Hostname" 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 -#: perms/templates/perms/asset_permission_list.html:70 msgid "Is active" 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" 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" 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" 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" 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" msgstr "åºåˆ—å·" -#: assets/models/asset.py:68 +#: assets/models/asset.py:69 msgid "CPU model" msgstr "CPUåž‹å·" -#: assets/models/asset.py:69 +#: assets/models/asset.py:70 msgid "CPU count" msgstr "CPUæ•°é‡" -#: assets/models/asset.py:70 +#: assets/models/asset.py:71 msgid "CPU cores" 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" msgstr "内å˜" -#: assets/models/asset.py:72 +#: assets/models/asset.py:73 msgid "Disk total" msgstr "硬盘大å°" -#: assets/models/asset.py:73 +#: assets/models/asset.py:74 msgid "Disk info" 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 msgid "OS" msgstr "æ“作系统" @@ -289,15 +296,21 @@ msgstr "系统架构" msgid "Hostname raw" msgstr "主机å原始" +#: assets/models/asset.py:81 assets/templates/assets/asset_create.html:33 +#: assets/templates/assets/asset_detail.html:220 +#: assets/templates/assets/asset_update.html:38 templates/_nav.html:27 +msgid "Labels" +msgstr "æ ‡ç¾ç®¡ç†" + #: assets/models/asset.py:82 assets/models/base.py:28 #: assets/models/cluster.py:28 assets/models/group.py:21 #: assets/templates/assets/admin_user_detail.html:68 #: assets/templates/assets/asset_detail.html:117 #: assets/templates/assets/domain_detail.html:72 #: assets/templates/assets/system_user_detail.html:96 -#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:22 perms/models.py:79 -#: perms/templates/perms/asset_permission_detail.html:94 -#: users/models/user.py:50 users/templates/users/user_detail.html:99 +#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:28 perms/models.py:72 +#: perms/templates/perms/asset_permission_detail.html:98 +#: users/models/user.py:55 users/templates/users/user_detail.html:99 msgid "Created by" msgstr "创建者" @@ -307,8 +320,8 @@ msgstr "创建者" #: assets/templates/assets/domain_detail.html:68 #: assets/templates/assets/system_user_detail.html:92 #: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:63 -#: perms/models.py:23 perms/models.py:80 -#: perms/templates/perms/asset_permission_detail.html:90 +#: perms/models.py:29 perms/models.py:73 +#: perms/templates/perms/asset_permission_detail.html:94 #: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17 #: users/templates/users/user_group_detail.html:63 msgid "Date created" @@ -325,10 +338,10 @@ msgstr "创建日期" #: assets/templates/assets/domain_list.html:17 #: assets/templates/assets/system_user_detail.html:100 #: assets/templates/assets/system_user_list.html:33 common/models.py:30 -#: ops/models/adhoc.py:42 perms/models.py:24 perms/models.py:81 -#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:26 +#: ops/models/adhoc.py:42 perms/models.py:30 perms/models.py:74 +#: perms/templates/perms/asset_permission_detail.html:102 terminal/models.py:26 #: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 -#: users/models/user.py:47 users/templates/users/user_detail.html:111 +#: users/models/user.py:52 users/templates/users/user_detail.html:111 #: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_list.html:14 #: users/templates/users/user_profile.html:114 @@ -351,7 +364,7 @@ msgstr "带宽" msgid "Contact" msgstr "è”系人" -#: assets/models/cluster.py:22 users/models/user.py:41 +#: assets/models/cluster.py:22 users/models/user.py:46 #: users/templates/users/user_detail.html:76 msgid "Phone" msgstr "手机" @@ -377,7 +390,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:13 -#: users/models/user.py:266 +#: users/models/user.py:285 msgid "System" msgstr "系统" @@ -389,14 +402,14 @@ msgstr "默认Cluster" msgid "Cluster" msgstr "集群" -#: assets/models/domain.py:45 assets/models/user.py:104 +#: assets/models/domain.py:45 assets/models/user.py:106 #: assets/templates/assets/domain_gateway_list.html:59 #: assets/templates/assets/system_user_detail.html:66 #: assets/templates/assets/system_user_list.html:28 msgid "Protocol" msgstr "åè®®" -#: assets/models/group.py:30 perms/models.py:18 +#: assets/models/group.py:30 msgid "Asset group" msgstr "资产组" @@ -406,15 +419,19 @@ msgstr "默认资产组" #: assets/models/label.py:14 audits/models.py:9 #: audits/templates/audits/ftp_log_list.html:33 -#: audits/templates/audits/ftp_log_list.html:71 perms/models.py:15 +#: audits/templates/audits/ftp_log_list.html:71 perms/forms.py:14 +#: perms/forms.py:31 perms/models.py:20 +#: perms/templates/perms/asset_permission_create_update.html:36 +#: perms/templates/perms/asset_permission_list.html:54 +#: perms/templates/perms/asset_permission_list.html:133 #: terminal/backends/command/models.py:10 terminal/models.py:122 #: terminal/templates/terminal/command_list.html:32 #: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/session_list.html:33 -#: terminal/templates/terminal/session_list.html:71 users/forms.py:220 -#: users/models/user.py:30 users/models/user.py:254 +#: terminal/templates/terminal/session_list.html:71 users/forms.py:219 +#: users/models/user.py:30 users/models/user.py:273 #: users/templates/users/user_group_detail.html:78 -#: users/templates/users/user_group_list.html:13 users/views/user.py:334 +#: users/templates/users/user_group_list.html:13 users/views/user.py:335 msgid "User" msgstr "用户" @@ -431,30 +448,49 @@ msgstr "分类" msgid "Key" msgstr "" -#: assets/models/user.py:103 +#: assets/models/user.py:104 +#: assets/templates/assets/_asset_group_bulk_update_modal.html:11 +#: assets/templates/assets/system_user_asset.html:21 +#: 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:102 assets/views/asset.py:49 +#: assets/views/asset.py:96 assets/views/asset.py:156 assets/views/asset.py:173 +#: assets/views/asset.py:197 assets/views/domain.py:29 +#: assets/views/domain.py:45 assets/views/domain.py:61 +#: assets/views/domain.py:74 assets/views/domain.py:98 +#: assets/views/domain.py:126 assets/views/domain.py:150 +#: assets/views/label.py:26 assets/views/label.py:42 assets/views/label.py:58 +#: assets/views/system_user.py:28 assets/views/system_user.py:44 +#: assets/views/system_user.py:60 assets/views/system_user.py:74 +#: templates/_nav.html:20 +msgid "Assets" +msgstr "资产管ç†" + +#: assets/models/user.py:105 msgid "Priority" msgstr "优先级" -#: assets/models/user.py:105 assets/templates/assets/_system_user.html:58 +#: assets/models/user.py:107 assets/templates/assets/_system_user.html:58 #: assets/templates/assets/system_user_detail.html:118 #: assets/templates/assets/system_user_update.html:11 msgid "Auto push" msgstr "自动推é€" -#: assets/models/user.py:106 assets/templates/assets/system_user_detail.html:70 +#: assets/models/user.py:108 assets/templates/assets/system_user_detail.html:70 msgid "Sudo" msgstr "Sudo" -#: assets/models/user.py:107 assets/templates/assets/system_user_detail.html:75 +#: assets/models/user.py:109 assets/templates/assets/system_user_detail.html:75 msgid "Shell" msgstr "Shell" -#: assets/models/user.py:150 audits/models.py:12 +#: assets/models/user.py:149 audits/models.py:12 #: audits/templates/audits/ftp_log_list.html:49 -#: audits/templates/audits/ftp_log_list.html:73 perms/forms.py:25 -#: perms/models.py:19 perms/models.py:76 -#: perms/templates/perms/asset_permission_detail.html:136 -#: perms/templates/perms/asset_permission_list.html:69 templates/_nav.html:26 +#: audits/templates/audits/ftp_log_list.html:73 perms/forms.py:43 +#: perms/models.py:24 perms/models.py:69 +#: perms/templates/perms/asset_permission_detail.html:140 +#: perms/templates/perms/asset_permission_list.html:58 +#: perms/templates/perms/asset_permission_list.html:145 templates/_nav.html:26 #: terminal/backends/command/models.py:12 terminal/models.py:124 #: terminal/templates/terminal/command_list.html:48 #: terminal/templates/terminal/command_list.html:74 @@ -468,41 +504,65 @@ msgstr "系统用户" msgid "%(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 "更新资产硬件信æ¯" msgstr "" -#: assets/tasks.py:132 +#: assets/tasks.py:135 msgid "定期更新资产硬件信æ¯" msgstr "" -#: assets/tasks.py:210 +#: assets/tasks.py:213 msgid "定期测试管ç†è´¦å·å¯è¿žæŽ¥æ€§: {}" msgstr "" -#: assets/tasks.py:217 +#: assets/tasks.py:220 msgid "测试管ç†è¡Œå·å¯è¿žæŽ¥æ€§: {}" msgstr "" -#: assets/tasks.py:227 +#: assets/tasks.py:230 msgid "测试资产å¯è¿žæŽ¥æ€§" msgstr "" -#: assets/tasks.py:297 +#: assets/tasks.py:300 msgid "Test system user connectability: {}" msgstr "测试系统用户å¯è¿žæŽ¥æ€§: {}" -#: assets/tasks.py:313 +#: assets/tasks.py:316 msgid "定期测试系统用户å¯è¿žæŽ¥æ€§: {}" msgstr "" -#: assets/tasks.py:392 -msgid "推é€ç³»ç»Ÿç”¨æˆ·åˆ°èŠ‚ç‚¹èµ„äº§: {} => {}" +#: assets/tasks.py:401 +msgid "推é€ç³»ç»Ÿç”¨æˆ·åˆ°å…¥èµ„产: {}" msgstr "" -#: assets/tasks.py:433 -msgid "推é€èŠ‚ç‚¹ç³»ç»Ÿç”¨æˆ·åˆ°æ–°åŠ å…¥èµ„äº§ä¸: {}" -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 msgid "Update asset group" @@ -512,28 +572,13 @@ msgstr "更新用户组" msgid "Hint: only change the field you want to update." msgstr "ä»…ä¿®æ”¹ä½ éœ€è¦æ›´æ–°çš„å—æ®µ" -#: assets/templates/assets/_asset_group_bulk_update_modal.html:11 -#: assets/templates/assets/system_user_asset.html:21 -#: 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: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:196 assets/views/domain.py:29 -#: assets/views/domain.py:45 assets/views/domain.py:61 -#: assets/views/domain.py:74 assets/views/domain.py:98 -#: assets/views/domain.py:126 assets/views/domain.py:150 -#: assets/views/label.py:26 assets/views/label.py:42 assets/views/label.py:58 -#: assets/views/system_user.py:28 assets/views/system_user.py:44 -#: assets/views/system_user.py:60 assets/views/system_user.py:74 -#: templates/_nav.html:20 -msgid "Assets" -msgstr "资产管ç†" - #: assets/templates/assets/_asset_group_bulk_update_modal.html:13 msgid "Select Asset" msgstr "选择资产" #: assets/templates/assets/_asset_group_bulk_update_modal.html:21 +#: assets/templates/assets/user_asset_list.html:48 +#: users/templates/users/user_granted_asset.html:47 msgid "System users" msgstr "系统用户" @@ -549,181 +594,16 @@ msgstr "二次验è¯" msgid "Import asset" msgstr "导入资产" -#: assets/templates/assets/_asset_import_modal.html:9 -#: users/templates/users/_user_import_modal.html:10 -msgid "Template" -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 -#: assets/templates/assets/user_asset_list.html:22 -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:23 perms/models.py:20 -#: perms/models.py:77 -#: perms/templates/perms/asset_permission_create_update.html:51 -#: perms/templates/perms/asset_permission_detail.html:116 -#: 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_granted_asset.html:47 -#: 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:72 -#: 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:72 -#: 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:121 -#: 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:122 -#: 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/_asset_list_modal.html:7 assets/views/asset.py:50 +#: templates/_nav.html:23 +msgid "Asset list" +msgstr "资产列表" #: assets/templates/assets/_system_user.html:37 #: assets/templates/assets/asset_create.html:16 #: assets/templates/assets/asset_update.html:21 #: assets/templates/assets/gateway_create_update.html:37 -#: perms/templates/perms/asset_permission_create_update.html:38 +#: perms/templates/perms/asset_permission_create_update.html:33 msgid "Basic" msgstr "基本" @@ -745,7 +625,7 @@ msgstr "自动生æˆå¯†é’¥" #: assets/templates/assets/asset_create.html:59 #: assets/templates/assets/asset_update.html:63 #: assets/templates/assets/gateway_create_update.html:53 -#: perms/templates/perms/asset_permission_create_update.html:49 +#: perms/templates/perms/asset_permission_create_update.html:45 #: terminal/templates/terminal/terminal_update.html:42 msgid "Other" msgstr "其它" @@ -762,7 +642,7 @@ msgstr "其它" #: common/templates/common/email_setting.html:59 #: common/templates/common/ldap_setting.html:59 #: common/templates/common/terminal_setting.html:101 -#: perms/templates/perms/asset_permission_create_update.html:71 +#: perms/templates/perms/asset_permission_create_update.html:69 #: terminal/templates/terminal/terminal_update.html:47 #: users/templates/users/_user.html:43 #: users/templates/users/user_bulk_update.html:23 @@ -774,6 +654,33 @@ msgstr "其它" msgid "Reset" 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_detail.html:18 #: assets/templates/assets/domain_detail.html:18 @@ -799,10 +706,19 @@ msgstr "资产列表" msgid "Asset list of " 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/system_user_asset.html:64 #: assets/templates/assets/system_user_detail.html:112 -#: perms/templates/perms/asset_permission_detail.html:110 +#: perms/templates/perms/asset_permission_detail.html:114 msgid "Quick update" msgstr "快速更新" @@ -818,15 +734,67 @@ msgstr "测试å¯è¿žæŽ¥æ€§" msgid "Test" 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 msgid "Replace node assets admin user with this" msgstr "替æ¢èµ„产的管ç†å‘˜" +#: assets/templates/assets/admin_user_detail.html:91 +#: perms/templates/perms/asset_permission_asset.html:116 +msgid "Select nodes" +msgstr "选择节点" + #: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/asset_detail.html:200 #: assets/templates/assets/asset_list.html:600 #: assets/templates/assets/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 #: users/templates/users/user_detail.html:339 #: users/templates/users/user_detail.html:364 @@ -855,20 +823,23 @@ msgstr "ä¸å¯è¾¾" msgid "Ratio" msgstr "比例" -#: assets/templates/assets/asset_create.html:29 -#: assets/templates/assets/asset_update.html:34 perms/models.py:74 -#: perms/templates/perms/asset_permission_create_update.html:40 -#: perms/templates/perms/asset_permission_list.html:67 -msgid "Node" -msgstr "节点" - -#: assets/templates/assets/asset_create.html:35 -#: assets/templates/assets/asset_list.html:75 -#: assets/templates/assets/asset_update.html:40 -msgid "Label" -msgstr "æ ‡ç¾" +#: 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:197 +#: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:198 msgid "Asset detail" msgstr "资产详情" @@ -893,6 +864,23 @@ msgstr "创建日期" msgid "Quick modify" 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 msgid "Refresh hardware" msgstr "更新硬件信æ¯" @@ -906,8 +894,7 @@ msgstr "刷新" msgid "Update successfully!" msgstr "æ›´æ–°æˆåŠŸ" -#: assets/templates/assets/asset_list.html:63 -#: assets/templates/assets/asset_list.html:120 assets/views/asset.py:96 +#: assets/templates/assets/asset_list.html:63 assets/views/asset.py:97 msgid "Create asset" msgstr "创建资产" @@ -921,35 +908,63 @@ msgstr "导入" msgid "Export" 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 msgid "Remove from this node" 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 -msgid "Add asset" -msgstr "æ·»åŠ èµ„äº§åˆ°èŠ‚ç‚¹" +msgid "Add node" +msgstr "新建节点" #: assets/templates/assets/asset_list.html:122 -msgid "Refresh node hardware info" -msgstr "更新节点资产硬件信æ¯" +msgid "Rename node" +msgstr "é‡å‘½å节点" #: assets/templates/assets/asset_list.html:123 -msgid "Test node connective" -msgstr "测试节点资产å¯è¿žæŽ¥æ€§" +msgid "Delete node" +msgstr "åˆ é™¤èŠ‚ç‚¹" #: assets/templates/assets/asset_list.html:125 -msgid "Add node" -msgstr "新建节点" +msgid "Add assets to node" +msgstr "æ·»åŠ èµ„äº§åˆ°èŠ‚ç‚¹" #: assets/templates/assets/asset_list.html:126 -msgid "Rename node" -msgstr "é‡å‘½å节点" +msgid "Move assets to node" +msgstr "移动资产到节点" #: assets/templates/assets/asset_list.html:128 -msgid "Delete node" -msgstr "åˆ é™¤èŠ‚ç‚¹" +msgid "Refresh node hardware info" +msgstr "更新节点资产硬件信æ¯" -#: assets/templates/assets/asset_list.html:203 +#: assets/templates/assets/asset_list.html:129 +msgid "Test node connective" +msgstr "测试节点资产å¯è¿žæŽ¥æ€§" + +#: assets/templates/assets/asset_list.html:204 msgid "Create node failed" msgstr "创建节点失败" @@ -957,6 +972,10 @@ msgstr "创建节点失败" msgid "Have child node, cancel" msgstr "å˜åœ¨å节点,ä¸èƒ½åˆ 除" +#: 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 #: users/templates/users/user_detail.html:334 @@ -1088,10 +1107,6 @@ msgstr "åˆ é™¤ç³»ç»Ÿç”¨æˆ·" msgid "System Users Deleting failed." msgstr "ç³»ç»Ÿç”¨æˆ·åˆ é™¤å¤±è´¥" -#: assets/templates/assets/user_asset_list.html:24 -msgid "Connective" -msgstr "连接性" - #: assets/views/admin_user.py:30 msgid "Admin user list" msgstr "管ç†ç”¨æˆ·åˆ—表" @@ -1104,23 +1119,19 @@ msgstr "更新管ç†ç”¨æˆ·" msgid "Admin user detail" msgstr "管ç†ç”¨æˆ·è¯¦æƒ…" -#: assets/views/asset.py:50 templates/_nav.html:23 -msgid "Asset list" -msgstr "资产列表" - -#: assets/views/asset.py:62 templates/_nav_user.html:4 +#: assets/views/asset.py:63 templates/_nav_user.html:4 msgid "My assets" msgstr "我的资产" -#: assets/views/asset.py:156 +#: assets/views/asset.py:157 msgid "Bulk update asset" msgstr "æ‰¹é‡æ›´æ–°èµ„产" -#: assets/views/asset.py:173 +#: assets/views/asset.py:174 msgid "Update asset" msgstr "更新资产" -#: assets/views/asset.py:300 +#: assets/views/asset.py:311 msgid "already exists" msgstr "å·²ç»å˜åœ¨" @@ -1182,18 +1193,33 @@ msgstr "远端地å€" msgid "Operate" msgstr "æ“作" -#: audits/models.py:14 audits/templates/audits/ftp_log_list.html:76 +#: audits/models.py:14 audits/templates/audits/ftp_log_list.html:56 +#: audits/templates/audits/ftp_log_list.html:76 msgid "Filename" msgstr "文件å" -#: audits/templates/audits/ftp_log_list.html:77 +#: audits/models.py:15 audits/templates/audits/ftp_log_list.html:77 +#: ops/templates/ops/task_list.html:39 +msgid "Success" +msgstr "æˆåŠŸ" + +#: audits/templates/audits/ftp_log_list.html:78 #: ops/templates/ops/adhoc_history.html:52 #: ops/templates/ops/adhoc_history_detail.html:61 -#: ops/templates/ops/task_history.html:58 terminal/models.py:132 +#: ops/templates/ops/task_history.html:58 perms/models.py:26 +#: perms/templates/perms/asset_permission_detail.html:86 terminal/models.py:132 #: terminal/templates/terminal/session_list.html:77 msgid "Date start" msgstr "开始日期" +#: audits/views.py:50 templates/_nav.html:64 +msgid "Audits" +msgstr "日志审计" + +#: audits/views.py:51 templates/_nav.html:67 +msgid "FTP log" +msgstr "FTP日志" + #: common/api.py:18 msgid "Test mail sent to {}, please check" msgstr "邮件已ç»å‘é€{}, 请检查" @@ -1655,10 +1681,6 @@ msgstr "æœç´¢" msgid "Versions" msgstr "版本" -#: ops/templates/ops/task_list.html:39 -msgid "Success" -msgstr "æˆåŠŸ" - #: ops/templates/ops/task_list.html:40 #: users/templates/users/login_log_list.html:54 msgid "Date" @@ -1685,24 +1707,37 @@ msgstr "任务列表" msgid "Task run history" msgstr "执行历å²" -#: perms/forms.py:22 perms/models.py:16 perms/models.py:75 -#: perms/templates/perms/asset_permission_list.html:68 templates/_nav.html:14 -#: users/models/group.py:25 users/models/user.py:37 +#: perms/forms.py:18 users/forms.py:176 users/forms.py:181 users/forms.py:193 +#: users/forms.py:223 +msgid "Select users" +msgstr "选择用户" + +#: perms/forms.py:34 perms/models.py:21 perms/models.py:68 +#: perms/templates/perms/asset_permission_list.html:55 +#: perms/templates/perms/asset_permission_list.html:136 templates/_nav.html:14 +#: users/models/group.py:25 users/models/user.py:42 #: users/templates/users/_select_user_modal.html:16 #: users/templates/users/user_detail.html:179 #: users/templates/users/user_list.html:26 msgid "User group" msgstr "用户组" -#: perms/models.py:21 perms/models.py:78 -#: perms/templates/perms/asset_permission_detail.html:86 -#: perms/templates/perms/asset_permission_list.html:71 users/models/user.py:49 -#: users/templates/users/user_detail.html:95 +#: perms/forms.py:56 +msgid "User or group at least one required" +msgstr "" + +#: perms/forms.py:65 +msgid "Asset or group at least one required" +msgstr "" + +#: perms/models.py:27 perms/models.py:71 +#: perms/templates/perms/asset_permission_detail.html:90 +#: users/models/user.py:54 users/templates/users/user_detail.html:95 #: users/templates/users/user_profile.html:96 msgid "Date expired" msgstr "失效日期" -#: perms/models.py:88 templates/_nav.html:34 +#: perms/models.py:81 templates/_nav.html:34 msgid "Asset permission" msgstr "资产授æƒ" @@ -1723,7 +1758,7 @@ msgid "Add asset to this permission" msgstr "æ·»åŠ èµ„äº§" #: perms/templates/perms/asset_permission_asset.html:97 -#: perms/templates/perms/asset_permission_detail.html:153 +#: perms/templates/perms/asset_permission_detail.html:157 #: perms/templates/perms/asset_permission_user.html:97 #: perms/templates/perms/asset_permission_user.html:125 #: users/templates/users/user_group_detail.html:95 @@ -1731,12 +1766,8 @@ msgid "Add" msgstr "æ·»åŠ " #: perms/templates/perms/asset_permission_asset.html:108 -msgid "Add asset group to this permission" -msgstr "æ·»åŠ èµ„äº§ç»„" - -#: perms/templates/perms/asset_permission_asset.html:116 users/forms.py:275 -msgid "Select asset groups" -msgstr "选择资产组" +msgid "Add node to this permission" +msgstr "æ·»åŠ èŠ‚ç‚¹" #: perms/templates/perms/asset_permission_asset.html:125 #: users/templates/users/user_detail.html:196 @@ -1756,18 +1787,18 @@ msgid "Asset count" msgstr "资产数é‡" #: perms/templates/perms/asset_permission_detail.html:78 -msgid "Asset group count" -msgstr "资产组数é‡" +msgid "Node count" +msgstr "节点数é‡" #: perms/templates/perms/asset_permission_detail.html:82 msgid "System user count" msgstr "系统用户数é‡" -#: perms/templates/perms/asset_permission_detail.html:144 users/forms.py:278 +#: perms/templates/perms/asset_permission_detail.html:148 msgid "Select system users" msgstr "选择系统用户" -#: perms/templates/perms/asset_permission_list.html:58 +#: perms/templates/perms/asset_permission_list.html:46 msgid "Create permission" msgstr "创建授æƒè§„则" @@ -1792,22 +1823,31 @@ msgstr "æ·»åŠ ç”¨æˆ·ç»„" msgid "Select user groups" msgstr "选择用户组" -#: perms/views.py:23 perms/views.py:47 perms/views.py:67 templates/_nav.html:31 +#: perms/views.py:25 perms/views.py:55 perms/views.py:70 perms/views.py:85 +#: perms/views.py:120 perms/views.py:151 templates/_nav.html:31 msgid "Perms" msgstr "æƒé™ç®¡ç†" -#: perms/views.py:24 +#: perms/views.py:26 msgid "Asset permission list" msgstr "资产授æƒåˆ—表" -#: perms/views.py:48 +#: perms/views.py:56 msgid "Create asset permission" msgstr "创建æƒé™è§„则" -#: perms/views.py:68 +#: perms/views.py:71 perms/views.py:86 msgid "Update asset permission" msgstr "更新资产授æƒ" +#: perms/views.py:121 +msgid "Asset permission user list" +msgstr "资产授æƒç”¨æˆ·åˆ—表" + +#: perms/views.py:152 +msgid "Asset permission asset list" +msgstr "资产授æƒèµ„产列表" + #: templates/_header_bar.html:18 msgid "Supports" msgstr "商业支æŒ" @@ -1816,13 +1856,13 @@ msgstr "商业支æŒ" msgid "Docs" msgstr "文档" -#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:94 +#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:93 #: users/templates/users/_user.html:36 #: users/templates/users/user_password_update.html:37 #: users/templates/users/user_profile.html:17 #: users/templates/users/user_profile_update.html:37 #: users/templates/users/user_profile_update.html:57 -#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:317 +#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:318 msgid "Profile" msgstr "个人信æ¯" @@ -1873,15 +1913,15 @@ msgstr "" "\"%(user_pubkey_update)s\"> 链接 </a> æ›´æ–°\n" " " -#: templates/_modal.html:15 +#: templates/_modal.html:21 msgid "Close" msgstr "å…³é—" #: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44 #: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95 -#: users/views/login.py:209 users/views/login.py:258 users/views/user.py:60 -#: users/views/user.py:75 users/views/user.py:94 users/views/user.py:150 -#: users/views/user.py:305 users/views/user.py:352 users/views/user.py:374 +#: users/views/login.py:205 users/views/login.py:254 users/views/user.py:60 +#: users/views/user.py:75 users/views/user.py:95 users/views/user.py:151 +#: users/views/user.py:306 users/views/user.py:353 users/views/user.py:375 msgid "Users" msgstr "用户管ç†" @@ -1925,14 +1965,6 @@ msgstr "终端管ç†" msgid "Job Center" msgstr "作业ä¸å¿ƒ" -#: templates/_nav.html:64 -msgid "Audits" -msgstr "日志审计" - -#: templates/_nav.html:67 -msgid "FTP log" -msgstr "FTP日志" - #: templates/captcha/image.html:3 msgid "Play CAPTCHA as audio file" msgstr "è¯è¨€æ’放验è¯ç " @@ -2199,7 +2231,7 @@ msgstr "" msgid "Invalid token or cache refreshed." msgstr "" -#: users/forms.py:28 users/models/user.py:38 +#: users/forms.py:27 users/models/user.py:43 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:87 #: users/templates/users/user_list.html:25 @@ -2207,55 +2239,55 @@ msgstr "" msgid "Role" msgstr "角色" -#: users/forms.py:30 users/forms.py:140 +#: users/forms.py:29 users/forms.py:139 msgid "ssh public key" msgstr "ssh公钥" -#: users/forms.py:31 users/forms.py:141 +#: users/forms.py:30 users/forms.py:140 msgid "ssh-rsa AAAA..." msgstr "" -#: users/forms.py:32 +#: users/forms.py:31 msgid "Paste user id_rsa.pub here." msgstr "å¤åˆ¶ç”¨æˆ·å…¬é’¥åˆ°è¿™é‡Œ" -#: users/forms.py:50 users/templates/users/user_detail.html:187 +#: users/forms.py:49 users/templates/users/user_detail.html:187 msgid "Join user groups" msgstr "æ·»åŠ åˆ°ç”¨æˆ·ç»„" -#: users/forms.py:60 users/forms.py:155 +#: users/forms.py:59 users/forms.py:154 msgid "Public key should not be the same as your old one." msgstr "ä¸èƒ½å’ŒåŽŸæ¥çš„密钥相åŒ" -#: users/forms.py:64 users/forms.py:159 users/serializers.py:42 +#: users/forms.py:63 users/forms.py:158 users/serializers.py:42 msgid "Not a valid ssh public key" msgstr "ssh密钥ä¸åˆæ³•" -#: users/forms.py:100 +#: users/forms.py:99 msgid "Old password" msgstr "原æ¥å¯†ç " -#: users/forms.py:105 +#: users/forms.py:104 msgid "New password" msgstr "新密ç " -#: users/forms.py:110 +#: users/forms.py:109 msgid "Confirm password" msgstr "确认密ç " -#: users/forms.py:120 +#: users/forms.py:119 msgid "Old password error" msgstr "原æ¥å¯†ç 错误" -#: users/forms.py:128 +#: users/forms.py:127 msgid "Password does not match" msgstr "密ç ä¸ä¸€è‡´" -#: users/forms.py:142 +#: users/forms.py:141 msgid "Paste your id_rsa.pub here." msgstr "å¤åˆ¶ä½ 的公钥到这里" -#: users/forms.py:170 users/models/user.py:46 +#: users/forms.py:169 users/models/user.py:51 #: users/templates/users/user_password_update.html:43 #: users/templates/users/user_profile.html:71 #: users/templates/users/user_profile_update.html:43 @@ -2263,10 +2295,6 @@ msgstr "å¤åˆ¶ä½ 的公钥到这里" msgid "Public key" msgstr "ssh公钥" -#: users/forms.py:177 users/forms.py:182 users/forms.py:194 users/forms.py:224 -msgid "Select users" -msgstr "选择用户" - #: users/models/authentication.py:36 msgid "Private Token" msgstr "ssh密钥" @@ -2291,7 +2319,7 @@ msgstr "Agent" msgid "Date login" msgstr "登录日期" -#: users/models/user.py:29 users/models/user.py:262 +#: users/models/user.py:29 users/models/user.py:281 msgid "Administrator" msgstr "管ç†å‘˜" @@ -2299,24 +2327,36 @@ msgstr "管ç†å‘˜" msgid "Application" msgstr "应用程åº" -#: users/models/user.py:36 users/templates/users/user_detail.html:71 +#: users/models/user.py:34 +msgid "Disable" +msgstr "ç¦ç”¨" + +#: users/models/user.py:35 +msgid "Enable" +msgstr "å¯ç”¨" + +#: users/models/user.py:36 +msgid "Force enable" +msgstr "强制å¯ç”¨" + +#: users/models/user.py:41 users/templates/users/user_detail.html:71 #: users/templates/users/user_profile.html:59 msgid "Email" msgstr "邮件" -#: users/models/user.py:39 +#: users/models/user.py:44 msgid "Avatar" msgstr "头åƒ" -#: users/models/user.py:40 users/templates/users/user_detail.html:82 +#: users/models/user.py:45 users/templates/users/user_detail.html:82 msgid "Wechat" msgstr "微信" -#: users/models/user.py:42 +#: users/models/user.py:47 msgid "Enable OTP" msgstr "二次验è¯" -#: users/models/user.py:265 +#: users/models/user.py:284 msgid "Administrator is the super user of system" msgstr "Administrator是åˆå§‹çš„超级管ç†å‘˜" @@ -2416,11 +2456,6 @@ msgstr "é‡ç½®å¯†ç " msgid "Password again" 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_list.html:16 users/views/user.py:75 msgid "Create user" @@ -2431,7 +2466,7 @@ msgid "Reset link will be generated and sent to the user. " msgstr "生æˆé‡ç½®å¯†ç 连接,通过邮件å‘é€ç»™ç”¨æˆ·" #: users/templates/users/user_detail.html:19 -#: users/templates/users/user_granted_asset.html:18 users/views/user.py:151 +#: users/templates/users/user_granted_asset.html:18 users/views/user.py:152 msgid "User detail" msgstr "用户详情" @@ -2550,8 +2585,8 @@ msgstr "ç”¨æˆ·åˆ é™¤å¤±è´¥" msgid "OTP" msgstr "" -#: users/templates/users/user_profile.html:100 users/views/user.py:180 -#: users/views/user.py:234 +#: users/templates/users/user_profile.html:100 users/views/user.py:181 +#: users/views/user.py:235 msgid "User groups" msgstr "用户组" @@ -2587,7 +2622,7 @@ msgstr "更新密钥" msgid "Or reset by server" msgstr "或者é‡ç½®å¹¶ä¸‹è½½å¯†é’¥" -#: users/templates/users/user_update.html:4 users/views/user.py:94 +#: users/templates/users/user_update.html:4 users/views/user.py:95 msgid "Update user" msgstr "更新用户" @@ -2733,78 +2768,78 @@ msgstr "更新用户组" msgid "User group granted asset" msgstr "用户组授æƒèµ„产" -#: users/views/login.py:57 +#: users/views/login.py:55 msgid "Please enable cookies and try again." msgstr "è®¾ç½®ä½ çš„æµè§ˆå™¨æ”¯æŒcookie" -#: users/views/login.py:99 +#: users/views/login.py:97 msgid "Logout success" msgstr "退出登录æˆåŠŸ" -#: users/views/login.py:100 +#: users/views/login.py:98 msgid "Logout success, return login page" msgstr "退出登录æˆåŠŸï¼Œè¿”å›žåˆ°ç™»å½•é¡µé¢" -#: users/views/login.py:116 +#: users/views/login.py:114 msgid "Email address invalid, please input again" msgstr "邮箱地å€é”™è¯¯ï¼Œé‡æ–°è¾“å…¥" -#: users/views/login.py:129 +#: users/views/login.py:127 msgid "Send reset password message" msgstr "å‘é€é‡ç½®å¯†ç 邮件" -#: users/views/login.py:130 +#: users/views/login.py:128 msgid "Send reset password mail success, login your mail box and follow it " msgstr "" "å‘é€é‡ç½®é‚®ä»¶æˆåŠŸ, 请登录邮箱查看, 按照æç¤ºæ“作 (如果没收到,请ç‰å¾…3-5分钟)" -#: users/views/login.py:144 +#: users/views/login.py:142 msgid "Reset password success" msgstr "é‡ç½®å¯†ç æˆåŠŸ" -#: users/views/login.py:145 +#: users/views/login.py:143 msgid "Reset password success, return to login page" msgstr "é‡ç½®å¯†ç æˆåŠŸï¼Œè¿”å›žåˆ°ç™»å½•é¡µé¢" -#: users/views/login.py:162 users/views/login.py:175 +#: users/views/login.py:160 users/views/login.py:173 msgid "Token invalid or expired" msgstr "Token错误或失效" -#: users/views/login.py:171 +#: users/views/login.py:169 msgid "Password not same" msgstr "密ç ä¸ä¸€è‡´" -#: users/views/login.py:209 +#: users/views/login.py:205 msgid "First login" msgstr "首次登陆" -#: users/views/login.py:259 +#: users/views/login.py:255 msgid "Login log list" msgstr "登录日志" -#: users/views/user.py:104 +#: users/views/user.py:105 msgid "Bulk update user success" msgstr "æ‰¹é‡æ›´æ–°ç”¨æˆ·æˆåŠŸ" -#: users/views/user.py:209 +#: users/views/user.py:210 msgid "Invalid file." msgstr "文件ä¸åˆæ³•" -#: users/views/user.py:306 +#: users/views/user.py:307 msgid "User granted assets" msgstr "用户授æƒèµ„产" -#: users/views/user.py:335 +#: users/views/user.py:336 msgid "Profile setting" msgstr "个人信æ¯è®¾ç½®" -#: users/views/user.py:353 +#: users/views/user.py:354 msgid "Password update" msgstr "å¯†ç æ›´æ–°" -#: users/views/user.py:375 +#: users/views/user.py:376 msgid "Public key update" msgstr "密钥更新" -#~ msgid "Task has been send, seen left asset status" -#~ msgstr "任务已下å‘,查看左侧资产状æ€" +#~ msgid "Add asset" +#~ msgstr "æ·»åŠ èµ„äº§åˆ°èŠ‚ç‚¹" diff --git a/apps/jumpserver/urls.py b/apps/jumpserver/urls.py index ced4797d5ef07a79c20b64d7435affb68731ea6a..8300ebe068aa9d3bc77666aac0a44b763bf411c7 100644 --- a/apps/jumpserver/urls.py +++ b/apps/jumpserver/urls.py @@ -36,9 +36,10 @@ urlpatterns = [ 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: urlpatterns += [ 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) - + ] diff --git a/apps/perms/api.py b/apps/perms/api.py index 1303e4128c1acafbef0a877ed9486a838027667e..be69d615842e713e6411645d13d3ae946ae7f48a 100644 --- a/apps/perms/api.py +++ b/apps/perms/api.py @@ -3,7 +3,7 @@ from django.shortcuts import get_object_or_404 from rest_framework.views import APIView, Response -from rest_framework.generics import ListAPIView, get_object_or_404 +from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView from rest_framework import viewsets from common.utils import set_or_append_attr_bulk @@ -98,6 +98,11 @@ class UserGrantedNodesApi(ListAPIView): nodes = AssetPermissionUtil.get_user_nodes_with_assets(user) return nodes.keys() + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + class UserGrantedNodesWithAssetsApi(ListAPIView): permission_classes = (IsSuperUserOrAppUser,) @@ -246,3 +251,77 @@ class ValidateUserAssetPermissionView(APIView): return Response({'msg': True}, status=200) else: return Response({'msg': False}, status=403) + + +class AssetPermissionRemoveUserApi(RetrieveUpdateAPIView): + """ + 将用户从授æƒä¸ç§»é™¤ï¼ŒDetail页é¢ä¼šè°ƒç”¨ + """ + permission_classes = (IsSuperUser,) + serializer_class = serializers.AssetPermissionUpdateUserSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + users = serializer.validated_data.get('users') + if users: + perm.users.remove(*tuple(users)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class AssetPermissionAddUserApi(RetrieveUpdateAPIView): + permission_classes = (IsSuperUser,) + serializer_class = serializers.AssetPermissionUpdateUserSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + users = serializer.validated_data.get('users') + if users: + perm.users.add(*tuple(users)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class AssetPermissionRemoveAssetApi(RetrieveUpdateAPIView): + """ + 将用户从授æƒä¸ç§»é™¤ï¼ŒDetail页é¢ä¼šè°ƒç”¨ + """ + permission_classes = (IsSuperUser,) + serializer_class = serializers.AssetPermissionUpdateAssetSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + assets = serializer.validated_data.get('assets') + if assets: + perm.assets.remove(*tuple(assets)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class AssetPermissionAddAssetApi(RetrieveUpdateAPIView): + permission_classes = (IsSuperUser,) + serializer_class = serializers.AssetPermissionUpdateAssetSerializer + queryset = AssetPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + assets = serializer.validated_data.get('assets') + if assets: + perm.assets.add(*tuple(assets)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) diff --git a/apps/perms/forms.py b/apps/perms/forms.py index 060812d4a19816b02e2f64941bdb91b8fbac1b38..c418160dd20697164f908db6855d45e346accb7f 100644 --- a/apps/perms/forms.py +++ b/apps/perms/forms.py @@ -4,10 +4,23 @@ from __future__ import absolute_import, unicode_literals from django import forms from django.utils.translation import ugettext_lazy as _ +from .hands import User from .models import AssetPermission class AssetPermissionForm(forms.ModelForm): + users = forms.ModelMultipleChoiceField( + queryset=User.objects.exclude(role=User.ROLE_APP), + label=_("User"), + widget=forms.SelectMultiple( + attrs={ + 'class': 'select2', + 'data-placeholder': _('Select users') + } + ), + required=False, + ) + class Meta: model = AssetPermission exclude = ( diff --git a/apps/perms/models.py b/apps/perms/models.py index 6609cd8e22f722d24e9faabe09c34903a6cef532..954cbe5f62865f8394a4bbeb9c31e0f12e1592a7 100644 --- a/apps/perms/models.py +++ b/apps/perms/models.py @@ -4,7 +4,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils import timezone -from common.utils import date_expired_default +from common.utils import date_expired_default, set_or_append_attr_bulk class ValidManager(models.Manager): @@ -45,6 +45,22 @@ class AssetPermission(models.Model): return True return False + def get_all_users(self): + users = set(self.users.all()) + for group in self.user_groups.all(): + _users = group.users.all() + set_or_append_attr_bulk(_users, 'inherit', group.name) + users.update(set(_users)) + return users + + def get_all_assets(self): + assets = set(self.assets.all()) + for node in self.nodes.all(): + _assets = node.get_all_assets() + set_or_append_attr_bulk(_assets, 'inherit', node.value) + assets.update(set(_assets)) + return assets + class NodePermission(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True) diff --git a/apps/perms/templates/perms/asset_permission_asset.html b/apps/perms/templates/perms/asset_permission_asset.html index 12369574da95283737b57d21d77307eb0dc934ff..364d7e60fe6cb934ebbe5f73f24677d00d7d154d 100644 --- a/apps/perms/templates/perms/asset_permission_asset.html +++ b/apps/perms/templates/perms/asset_permission_asset.html @@ -57,12 +57,12 @@ </tr> </thead> <tbody> - {% for asset in page_obj %} + {% for asset in object_list %} <tr> <td>{{ asset.hostname }}</td> <td>{{ asset.ip }}</td> <td> - <button title="{{ asset.inherit_from_asset_groups }}" data-gid="{{ asset.id }}" class="btn btn-danger btn-xs btn-remove-asset {% if asset.is_inherit_from_asset_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button> + <button title="{{ asset.inherit }}" data-gid="{{ asset.id }}" class="btn btn-danger btn-xs btn-remove-asset {% if asset.inherit %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button> </td> </tr> {% endfor %} @@ -85,9 +85,9 @@ <form> <tr class="no-borders-tr"> <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 %} - <option value="{{ asset.id }}">{{ asset.hostname }}</option> + <option value="{{ asset.id }}">{{ asset }}</option> {% endfor %} </select> </td> @@ -105,7 +105,7 @@ <div class="panel panel-info"> <div class="panel-heading"> - <i class="fa fa-info-circle"></i> {% trans 'Add asset group to this permission' %} + <i class="fa fa-info-circle"></i> {% trans 'Add node to this permission' %} </div> <div class="panel-body"> <table class="table group_edit"> @@ -113,25 +113,25 @@ <form> <tr> <td colspan="2" class="no-borders"> - <select data-placeholder="{% trans 'Select asset groups' %}" class="select2 group" style="width: 100%" multiple="" tabindex="4"> - {% for asset_group in asset_groups_remain %} - <option value="{{ asset_group.id }}" id="opt_{{ asset_group.id }}">{{ asset_group.name }}</option> + <select data-placeholder="{% trans 'Select nodes' %}" class="select2" id="node_select2" style="width: 100%" multiple="" tabindex="4"> + {% for node in nodes_remain %} + <option value="{{ node.id }}" id="opt_{{ node.id }}">{{ node }}</option> {% endfor %} </select> </td> </tr> <tr> <td colspan="2" class="no-borders"> - <button type="button" class="btn btn-info btn-sm" id="btn-add-group">{% trans 'Join' %}</button> + <button type="button" class="btn btn-info btn-sm" id="btn-add-node">{% trans 'Join' %}</button> </td> </tr> </form> - {% for asset_group in asset_groups %} + {% for node in asset_permission.nodes.all %} <tr> - <td ><b class="bdg_user_group" data-gid={{ asset_group.id }}>{{ asset_group.name }}</b></td> + <td ><b class="bdg_group" data-gid={{ node.id }}>{{ node }}</b></td> <td> - <button class="btn btn-danger btn-xs btn-remove-group" 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> </tr> {% endfor %} @@ -179,49 +179,30 @@ function removeAssets(assets) { }); } -function updateGroup(groups) { +function updateNodes(nodes, success) { var the_url = "{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}"; var body = { - asset_groups: groups + nodes: nodes }; APIUpdateAttr({ url: the_url, - body: JSON.stringify(body) + body: JSON.stringify(body), + success: success }); } -jumpserver.assets_selected = {}; -jumpserver.nodes_selected = {}; $(document).ready(function () { - $('.select2.asset').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] - }) + $('.select2').select2(); }) .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; } - var assets = []; - $.map(jumpserver.assets_selected, function(value, index) { - assets.push(index); - }); - addAssets(assets); + addAssets(assets_selected); }) .on('click', '.btn-remove-asset', function () { var asset_id = $(this).data("gid"); @@ -231,38 +212,44 @@ $(document).ready(function () { var assets = [asset_id]; removeAssets(assets) }) -.on('click', '#btn-add-group', function () { - if (Object.keys(jumpserver.nodes_selected).length === 0) { +.on('click', '#btn-add-node', function () { + 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; } - - var groups = $('.bdg_group').map(function() { + var nodes_origin = $('.bdg_group').map(function() { return $(this).data('gid'); }).get(); - $.map(jumpserver.nodes_selected, function(group_name, index) { - groups.push(index); - $('#opt_' + index).remove(); - $('.group_edit tbody').append( - '<tr>' + - '<td><b class="bdg_group" data-gid="' + index + '">' + group_name + '</b></td>' + - '<td><button class="btn btn-danger btn-xs pull-right btn-leave-group" type="button"><i class="fa fa-minus"></i></button></td>' + - '</tr>' - ) - }); - - updateGroup(groups); + var nodes = nodes_origin.concat(Object.keys(nodes_selected)); + var success = function () { + $.map(nodes_selected, function(name, id) { + $('#opt_' + id).remove(); + $('.group_edit tbody').append( + '<tr>' + + '<td><b class="bdg_group" data-gid="' + id + '">' + name + '</b></td>' + + '<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, success); }) -.on('click', '.btn-remove-group', function () { +.on('click', '.btn-remove-node', function () { var $this = $(this); var $tr = $this.closest('tr'); - var groups = $('.bdg_group').map(function() { + var nodes = $('.bdg_group').map(function() { if ($(this).data('gid') !== $this.data('gid')){ return $(this).data('gid'); } }).get(); - updateGroup(groups); - $tr.remove() + var success = function () { + $tr.remove() + }; + updateNodes(nodes, success); }) </script> {% endblock %} diff --git a/apps/perms/templates/perms/asset_permission_create_update.html b/apps/perms/templates/perms/asset_permission_create_update.html index 19704485672875ecaa8718c505a4a7aa8d35ee6d..551aab142e829c5bc25c8dd4f14193f0c5ebd053 100644 --- a/apps/perms/templates/perms/asset_permission_create_update.html +++ b/apps/perms/templates/perms/asset_permission_create_update.html @@ -76,20 +76,37 @@ </div> </div> </div> + {% include 'assets/_asset_list_modal.html' %} {% endblock %} {% block custom_foot_js %} - <script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script> - <script> - $(document).ready(function () { - $('.select2').select2(); - $('#datepicker').datepicker({ - format: "yyyy-mm-dd", - todayBtn: "linked", - keyboardNavigation: false, - forceParse: false, - calendarWeeks: true, - autoclose: true - }); - }) - </script> +<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script> +<script> +$(document).ready(function () { + $('.select2').select2({ + closeOnSelect: false + }); + $('#datepicker').datepicker({ + format: "yyyy-mm-dd", + todayBtn: "linked", + keyboardNavigation: false, + forceParse: false, + calendarWeeks: true, + autoclose: true + }); + $("#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 %} \ No newline at end of file diff --git a/apps/perms/templates/perms/asset_permission_detail.html b/apps/perms/templates/perms/asset_permission_detail.html index 5540ca515243c7878613a16edb2696cdae3d0fd4..3996cb274b8b328f7d8e582d9816d693ac91db49 100644 --- a/apps/perms/templates/perms/asset_permission_detail.html +++ b/apps/perms/templates/perms/asset_permission_detail.html @@ -15,19 +15,19 @@ <div class="panel-options"> <ul class="nav nav-tabs"> <li class="active"> - <a href="{% url 'perms:asset-permission-detail' pk=asset_permission.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a> + <a href="{% url 'perms:asset-permission-detail' pk=object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a> </li> <li> - <a href="{% url 'perms:asset-permission-user-list' pk=asset_permission.id %}" class="text-center"> + <a href="{% url 'perms:asset-permission-user-list' pk=object.id %}" class="text-center"> <i class="fa fa-bar-chart-o"></i> {% trans 'Users and user groups' %} </a> </li> <li> - <a href="{% url 'perms:asset-permission-asset-list' pk=asset_permission.id %}" class="text-center"> + <a href="{% url 'perms:asset-permission-asset-list' pk=object.id %}" class="text-center"> <i class="fa fa-bar-chart-o"></i> {% trans 'Assets and asset groups' %}</a> </li> <li class="pull-right"> - <a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a> + <a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=object.id %}"><i class="fa fa-edit"></i>{% trans 'Update' %}</a> </li> <li class="pull-right"> <a class="btn btn-outline btn-danger btn-delete-perm"> @@ -40,7 +40,7 @@ <div class="col-sm-7" style="padding-left: 0;"> <div class="ibox float-e-margins"> <div class="ibox-title"> - <span class="label"><b>{{ asset_permission.name }}</b></span> + <span class="label"><b>{{ object.name }}</b></span> <div class="ibox-tools"> <a class="collapse-link"> <i class="fa fa-chevron-up"></i> @@ -60,43 +60,47 @@ <tbody> <tr class="no-borders-tr"> <td>{% trans 'Name' %}:</td> - <td><b>{{ asset_permission.name }}</b></td> + <td><b>{{ object.name }}</b></td> </tr> <tr> <td>{% trans 'User count' %}:</td> - <td><b>{{ asset_permission.users.count }}</b></td> + <td><b>{{ object.users.count }}</b></td> </tr> <tr> <td>{% trans 'User group count' %}:</td> - <td><b>{{ asset_permission.users.count }}</b></td> + <td><b>{{ object.users.count }}</b></td> </tr> <tr> <td>{% trans 'Asset count' %}:</td> - <td><b>{{ asset_permission.assets.count }}</b></td> + <td><b>{{ object.assets.count }}</b></td> </tr> <tr> - <td>{% trans 'Asset group count' %}:</td> - <td><b>{{ asset_permission.asset_groups.count }}</b></td> + <td>{% trans 'Node count' %}:</td> + <td><b>{{ object.nodes.count }}</b></td> </tr> <tr> <td>{% trans 'System user count' %}:</td> - <td><b>{{ asset_permission.system_users.count }}</b></td> + <td><b>{{ object.system_users.count }}</b></td> + </tr> + <tr> + <td>{% trans 'Date start' %}:</td> + <td><b>{{ object.date_start }}</b></td> </tr> <tr> <td>{% trans 'Date expired' %}:</td> - <td><b>{{ asset_permission.date_expired }}</b></td> + <td><b>{{ object.date_expired }}</b></td> </tr> <tr> <td>{% trans 'Date created' %}:</td> - <td><b>{{ asset_permission.date_created }}</b></td> + <td><b>{{ object.date_created }}</b></td> </tr> <tr> <td>{% trans 'Created by' %}:</td> - <td><b>{{ asset_permission.created_by }}</b></td> + <td><b>{{ object.created_by }}</b></td> </tr> <tr> <td>{% trans 'Comment' %}:</td> - <td><b>{{ asset_permission.comment }}</b></td> + <td><b>{{ object.comment }}</b></td> </tr> </tbody> </table> @@ -117,7 +121,7 @@ <td><span style="float: right"> <div class="switch"> <div class="onoffswitch"> - <input type="checkbox" {% if asset_permission.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active"> + <input type="checkbox" {% if object.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active"> <label class="onoffswitch-label" for="is_active"> <span class="onoffswitch-inner"></span> <span class="onoffswitch-switch"></span> @@ -143,7 +147,7 @@ <td colspan="2"> <select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4"> {% 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 %} </select> </td> @@ -155,9 +159,9 @@ </tr> </form> - {% for system_user in system_users %} + {% for system_user in object.system_users.all %} <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> <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> @@ -179,7 +183,7 @@ jumpserver.system_users_selected = {}; function updateSystemUser(system_users) { - var the_url = "{% url 'api-perms:asset-permission-detail' pk=asset_permission.id %}"; + var the_url = "{% url 'api-perms:asset-permission-detail' pk=object.id %}"; var body = { system_users: Object.assign([], system_users) }; @@ -203,7 +207,7 @@ $(document).ready(function () { .on('click', '.btn-delete-perm', function () { var $this = $(this); var name = "{{ asset_permission.name }}"; - var uid = "{{ asset_permission.id }}"; + var uid = "{{ object.id }}"; var the_url = '{% url "api-perms:asset-permission-detail" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid); var redirect_url = "{% url 'perms:asset-permission-list' %}"; objectDelete($this, name, the_url, redirect_url); @@ -238,7 +242,7 @@ $(document).ready(function () { updateSystemUser(system_users); $tr.remove() }).on('click', '#is_active', function () { - var the_url = '{% url "api-perms:asset-permission-detail" pk=asset_permission.id %}'; + var the_url = '{% url "api-perms:asset-permission-detail" pk=object.id %}'; var checked = $(this).prop('checked'); var body = { 'is_active': checked diff --git a/apps/perms/templates/perms/asset_permission_user.html b/apps/perms/templates/perms/asset_permission_user.html index bee5b0e35acb2c8037e2b2e9f725a57876fd9fc8..5d490bc280566302f7a848c4717fc0aa3d5eb118 100644 --- a/apps/perms/templates/perms/asset_permission_user.html +++ b/apps/perms/templates/perms/asset_permission_user.html @@ -57,12 +57,12 @@ </tr> </thead> <tbody> - {% for user in page_obj %} + {% for user in object_list %} <tr> <td>{{ user.name }}</td> <td>{{ user.username }}</td> <td> - <button class="btn btn-danger btn-xs btn-remove-user {% if user.is_inherit_from_user_groups %} disabled {% endif %}" data-gid="{{ user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button> + <button class="btn btn-danger btn-xs btn-remove-user {% if user.inherit %} disabled {% endif %}" data-gid="{{ user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button> </td> </tr> {% endfor %} @@ -87,7 +87,7 @@ <td colspan="2"> <select data-placeholder="{% trans 'Select user' %}" class="select2 user" style="width: 100%" multiple="" tabindex="4"> {% for user in users_remain %} - <option value="{{ user.id }}">{{ user.name }}</option> + <option value="{{ user.id }}">{{ user }}</option> {% endfor %} </select> </td> @@ -115,7 +115,7 @@ <td colspan="2" class="no-borders"> <select data-placeholder="{% trans 'Select user groups' %}" class="select2 user-group" style="width: 100%" multiple="" tabindex="4"> {% 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 %} </select> </td> @@ -127,9 +127,9 @@ </tr> </form> - {% for user_group in user_groups %} + {% for user_group in asset_permission.user_groups.all %} <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> <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> diff --git a/apps/perms/urls/api_urls.py b/apps/perms/urls/api_urls.py index d114e4f0b32b43336faf0a899ac3aaffbe3c4b80..f15450141563499b3bc297a09e3dc14ab4b739f6 100644 --- a/apps/perms/urls/api_urls.py +++ b/apps/perms/urls/api_urls.py @@ -11,20 +11,50 @@ router.register('v1/asset-permissions', api.AssetPermissionViewSet, 'asset-permi urlpatterns = [ # 查询æŸä¸ªç”¨æˆ·æŽˆæƒçš„资产和资产组 - url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.UserGrantedAssetsApi.as_view(), name='user-assets'), - url(r'^v1/user/assets/$', api.UserGrantedAssetsApi.as_view(), name='my-assets'), - url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$', api.UserGrantedNodesApi.as_view(), name='user-nodes'), - url(r'^v1/user/nodes/$', api.UserGrantedNodesApi.as_view(), name='my-nodes'), - url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$', api.UserGrantedNodeAssetsApi.as_view(), name='user-node-assets'), - url(r'^v1/user/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$', api.UserGrantedNodeAssetsApi.as_view(), name='my-node-assets'), - url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$', api.UserGrantedNodesWithAssetsApi.as_view(), name='user-nodes-assets'), - url(r'^v1/user/nodes-assets/$', api.UserGrantedNodesWithAssetsApi.as_view(), name='my-nodes-assets'), + url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', + api.UserGrantedAssetsApi.as_view(), name='user-assets'), + url(r'^v1/user/assets/$', api.UserGrantedAssetsApi.as_view(), + name='my-assets'), + url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$', + api.UserGrantedNodesApi.as_view(), name='user-nodes'), + url(r'^v1/user/nodes/$', api.UserGrantedNodesApi.as_view(), + name='my-nodes'), + url( + r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$', + api.UserGrantedNodeAssetsApi.as_view(), name='user-node-assets'), + url(r'^v1/user/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$', + api.UserGrantedNodeAssetsApi.as_view(), name='my-node-assets'), + url(r'^v1/user/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$', + api.UserGrantedNodesWithAssetsApi.as_view(), name='user-nodes-assets'), + url(r'^v1/user/nodes-assets/$', api.UserGrantedNodesWithAssetsApi.as_view(), + name='my-nodes-assets'), # 查询æŸä¸ªç”¨æˆ·ç»„授æƒçš„资产和资产组 - url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'), - url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'), - url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$', api.UserGroupGrantedNodesWithAssetsApi.as_view(), name='user-group-nodes-assets'), - url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$', api.UserGroupGrantedNodeAssetsApi.as_view(), name='user-group-node-assets'), + url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/assets/$', + api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'), + url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/$', + api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'), + url(r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes-assets/$', + api.UserGroupGrantedNodesWithAssetsApi.as_view(), + name='user-group-nodes-assets'), + url( + r'^v1/user-group/(?P<pk>[0-9a-zA-Z\-]{36})/nodes/(?P<node_id>[0-9a-zA-Z\-]{36})/assets/$', + api.UserGroupGrantedNodeAssetsApi.as_view(), + name='user-group-node-assets'), + + # 用户和资产授æƒå˜æ›´ + url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/user/remove/$', + api.AssetPermissionRemoveUserApi.as_view(), + name='asset-permission-remove-user'), + url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/user/add/$', + api.AssetPermissionAddUserApi.as_view(), + name='asset-permission-add-user'), + url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/asset/remove/$', + api.AssetPermissionRemoveAssetApi.as_view(), + name='asset-permission-remove-asset'), + url(r'^v1/asset-permissions/(?P<pk>[0-9a-zA-Z\-]{36})/asset/add/$', + api.AssetPermissionAddAssetApi.as_view(), + name='asset-permission-add-asset'), # 验è¯ç”¨æˆ·æ˜¯å¦æœ‰æŸä¸ªèµ„产和系统用户的æƒé™ url(r'v1/asset-permission/user/validate/$', api.ValidateUserAssetPermissionView.as_view(), name='validate-user-asset-permission'), diff --git a/apps/perms/urls/views_urls.py b/apps/perms/urls/views_urls.py index a1acc570c9c6a292de6494187fd692a794249406..5c3fa3b485c206edc5d3a289657126d303365788 100644 --- a/apps/perms/urls/views_urls.py +++ b/apps/perms/urls/views_urls.py @@ -11,8 +11,8 @@ urlpatterns = [ url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/update$', views.AssetPermissionUpdateView.as_view(), name='asset-permission-update'), url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})$', views.AssetPermissionDetailView.as_view(),name='asset-permission-detail'), url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/delete$', views.AssetPermissionDeleteView.as_view(), name='asset-permission-delete'), - # url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'), - # url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'), + url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/user$', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'), + url(r'^asset-permission/(?P<pk>[0-9a-zA-Z\-]{36})/asset$', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'), ] diff --git a/apps/perms/views.py b/apps/perms/views.py index 2aa1ddd8b615a230bcf4be65a808088f998de2af..8babf519f03db30096b97ba4af24b04293f3c58b 100644 --- a/apps/perms/views.py +++ b/apps/perms/views.py @@ -4,12 +4,12 @@ from __future__ import unicode_literals, absolute_import from django.utils.translation import ugettext as _ from django.views.generic import ListView, CreateView, UpdateView, DetailView -from django.views.generic.edit import DeleteView +from django.views.generic.edit import DeleteView, SingleObjectMixin from django.urls import reverse_lazy from django.conf import settings -from common.utils import is_uuid -from .hands import AdminUserRequiredMixin, Node, Asset +from common.mixins import AdminUserRequiredMixin +from .hands import Node, Asset, SystemUser, User, UserGroup from .models import AssetPermission from .forms import AssetPermissionForm @@ -83,7 +83,11 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = { 'app': _('Perms'), - 'action': _('Update asset permission') + 'action': _('Update asset permission'), + 'system_users_remain': SystemUser.objects.exclude( + granted_by_permissions=self.object + ), + } kwargs.update(context) return super().get_context_data(**kwargs) @@ -95,3 +99,59 @@ class AssetPermissionDeleteView(AdminUserRequiredMixin, DeleteView): success_url = reverse_lazy('perms:asset-permission-list') +class AssetPermissionUserView(AdminUserRequiredMixin, + SingleObjectMixin, + ListView): + template_name = 'perms/asset_permission_user.html' + context_object_name = 'asset_permission' + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + object = None + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=AssetPermission.objects.all()) + return super().get(request, *args, **kwargs) + + def get_queryset(self): + queryset = self.object.get_all_users() + return queryset + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Asset permission user list'), + 'users_remain': User.objects.exclude(asset_permissions=self.object) + .exclude(role=User.ROLE_APP), + 'user_groups_remain': UserGroup.objects.exclude( + asset_permissions=self.object + ) + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class AssetPermissionAssetView(AdminUserRequiredMixin, + SingleObjectMixin, + ListView): + template_name = 'perms/asset_permission_asset.html' + context_object_name = 'asset_permission' + paginate_by = settings.CONFIG.DISPLAY_PER_PAGE + object = None + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=AssetPermission.objects.all()) + return super().get(request, *args, **kwargs) + + def get_queryset(self): + queryset = self.object.get_all_assets() + return queryset + + def get_context_data(self, **kwargs): + assets_granted = self.get_queryset() + context = { + 'app': _('Perms'), + 'action': _('Asset permission asset list'), + 'assets_remain': Asset.objects.exclude(id__in=[a.id for a in assets_granted]), + 'nodes_remain': Node.objects.exclude(granted_by_permissions=self.object), + } + kwargs.update(context) + return super().get_context_data(**kwargs) \ No newline at end of file diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index f2f8b8f55345b7542f7c93c53bc3725e722cb205..4614550854c12f6c36ed1dc12b83f8c3c3df95d3 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -307,7 +307,7 @@ jumpserver.initDataTable = function (options) { 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) { var $node = table[ type ]( indexes ).nodes().to$(); @@ -446,22 +446,56 @@ jumpserver.initServerSideDataTable = function (options) { 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) { var $node = table[ type ]( indexes ).nodes().to$(); $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) { var $node = table[ type ]( indexes ).nodes().to$(); $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(){ $('#op').html(options.op_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")) { $(this).closest('table').find('.ipt_check').prop('checked', true); table.rows({search:'applied', page:'current'}).select(); diff --git a/apps/templates/_footer.html b/apps/templates/_footer.html index c9641c4fa3f6f0a3984e71ca242a31baf3191720..dbe60e1bc512a42948e347c641333206712c8ab5 100644 --- a/apps/templates/_footer.html +++ b/apps/templates/_footer.html @@ -1,6 +1,6 @@ <div class="footer fixed"> <div class="pull-right"> - Version <strong>1.0.0-{% include '_build.html' %}</strong> GPLv2. + Version <strong>1.2.0-{% include '_build.html' %}</strong> GPLv2. <img style="display: none" src="http://www.jumpserver.org/img/evaluate_avatar1.jpg"> </div> <div> diff --git a/apps/templates/_modal.html b/apps/templates/_modal.html index ad7f21ccc0b55352d9d3fcf1222e8cc4c0346595..e84586d0c05b81ed0067d986d422c81d8e657657 100644 --- a/apps/templates/_modal.html +++ b/apps/templates/_modal.html @@ -1,4 +1,9 @@ {% 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 class="modal-dialog {% block modal_class %}{% endblock %}"> <div class="modal-content animated fadeIn"> @@ -12,8 +17,10 @@ {% endblock %} </div> <div class="modal-footer"> + {% block modal_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> + {% endblock %} </div> </div> </div> diff --git a/apps/templates/_nav.html b/apps/templates/_nav.html index 409a46f151c5ed5e6ada846a5db738206d193001..e0d58080b851157e8cd676a1d5f795f68243bde1 100644 --- a/apps/templates/_nav.html +++ b/apps/templates/_nav.html @@ -61,7 +61,7 @@ </li> <li id="audits"> <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> <ul class="nav nav-second-level"> <li id="ftp-log"><a href="{% url 'audits:ftp-log-list' %}">{% trans 'FTP log' %}</a></li> diff --git a/apps/terminal/api.py b/apps/terminal/api.py index 8247ac27cb56221830f3012c2c8b0fbf11adc6b8..e625e17bcaf07e5c77a90a9ff4e60da4bcc8bec2 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -248,7 +248,7 @@ class CommandViewSet(viewsets.ViewSet): class SessionReplayViewSet(viewsets.ViewSet): serializer_class = ReplaySerializer - permission_classes = () + permission_classes = (IsSuperUserOrAppUser,) session = None def gen_session_path(self): diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 365f3428c2030f568852894a21de367a17b968c3..4674fe5192431a113cd03f058acad5405a41161b 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -45,7 +45,7 @@ class User(AbstractUser): wechat = models.CharField(max_length=128, blank=True, verbose_name=_('Wechat')) 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_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 _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')) @@ -55,7 +55,7 @@ class User(AbstractUser): created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by')) def __str__(self): - return self.username + return '{0.name}({0.username})'.format(self) @property def password_raw(self): @@ -70,6 +70,14 @@ class User(AbstractUser): def password_raw(self, 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): return reverse('users:user-detail', args=(self.id,)) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 71a0f742bb148b498a84b86815a00efa5e4ef87c..58aac783cfa1b7af98159098c31949bb57f9ee02 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -13,7 +13,7 @@ Docker 安装è§: `Docker官方安装文档 <https://docs.docker.com/install/>`_ ``````````````` 使用 root 命令行输入:: - $ docker run -d -p 8080:80 -p 2222:2222 registry.jumpserver.org/public/jumpserver:latest + $ docker run -d -p 8080:80 -p 2222:2222 registry.jumpserver.org/public/jumpserver:1.0.0 访问 ``````````````` @@ -42,10 +42,13 @@ XShellç‰å·¥å…·è¯·æ·»åŠ connection连接 :: - docker run -d -p 8080:80 -p 2222:2222 -e DB_ENGINE=mysql -e DB_HOST=192.168.1.1 -e DB_PORT=3306 -e DB_USER=root -e DB_PASSWORD=xxx -e DB_NAME=jumpserver registry.jumpserver.org/public/jumpserver:latest + docker run -d -p 8080:80 -p 2222:2222 -e DB_ENGINE=mysql -e DB_HOST=192.168.1.1 -e DB_PORT=3306 -e DB_USER=root -e DB_PASSWORD=xxx -e DB_NAME=jumpserver registry.jumpserver.org/public/jumpserver:1.0.0 ä»“åº“åœ°å€ ``````````````` https://github.com/jumpserver/Dockerfile + + + diff --git a/docs/step_by_step.rst b/docs/step_by_step.rst index 21903a73bac2b5d03cd1ea1b20589a1498ccf272..484013e1bc1b6e2959a636b9dab70e051670bfff 100644 --- a/docs/step_by_step.rst +++ b/docs/step_by_step.rst @@ -49,7 +49,7 @@ # 看到下é¢çš„æç¤ºç¬¦ä»£è¡¨æˆåŠŸï¼Œä»¥åŽè¿è¡Œ Jumpserver 都è¦å…ˆè¿è¡Œä»¥ä¸Š source 命令,以下所有命令å‡åœ¨è¯¥è™šæ‹ŸçŽ¯å¢ƒä¸è¿è¡Œ (py3) [root@localhost py3] -二. 安装 Jumpserver 0.5.0 +二. 安装 Jumpserver 1.0.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **2.1 下载或 Clone 项目** @@ -201,7 +201,7 @@ Luna 已改为纯å‰ç«¯ï¼Œéœ€è¦ Nginx æ¥è¿è¡Œè®¿é—® -访问(https://github.com/jumpserver/luna/releases)下载对应 release 包,直接解压,ä¸éœ€è¦ç¼–译 +访问(https://github.com/jumpserver/luna/releases)下载对应版本的 release 包,直接解压,ä¸éœ€è¦ç¼–译 4.1 解压 Luna @@ -228,7 +228,7 @@ Luna 已改为纯å‰ç«¯ï¼Œéœ€è¦ Nginx æ¥è¿è¡Œè®¿é—® -p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \ -e JUMPSERVER_KEY_DIR=/config/guacamole/key \ -e JUMPSERVER_SERVER=http://<填写本机的IP地å€>:8080 \ - registry.jumpserver.org/public/guacamole:latest + registry.jumpserver.org/public/guacamole:1.0.0 è¿™é‡Œæ‰€éœ€è¦æ³¨æ„的是 guacamole 暴露出æ¥çš„ç«¯å£æ˜¯ 8081,若与主机上其他端å£å†²çªè¯·è‡ªå®šä¹‰ä¸€ä¸‹ã€‚ diff --git a/utils/2018_04_11_migrate_permissions.sh b/utils/2018_04_11_migrate_permissions.sh index 5f98e5d4a30378bf57172d68bb9bbc671baea227..bbc29c3889f94945d718f3f86d8a215a96aed695 100644 --- a/utils/2018_04_11_migrate_permissions.sh +++ b/utils/2018_04_11_migrate_permissions.sh @@ -3,9 +3,10 @@ python ../apps/manage.py shell << EOF from perms.models import * +from assets.models import SystemUser for old in NodePermission.objects.all(): - perm = asset_perm_model.objects.using(db_alias).create( + perm = AssetPermission.objects.create( name="{}-{}-{}".format( old.node.value, old.user_group.name, @@ -20,5 +21,10 @@ for old in NodePermission.objects.all(): perm.user_groups.add(old.user_group) perm.nodes.add(old.node) perm.system_users.add(old.system_user) + + for s in SystemUser.objects.all(): + nodes = list(s.nodes.all()) + s.nodes.set([]) + s.nodes.set(nodes) EOF