mirror of https://github.com/jumpserver/jumpserver
Bugfix (#2938)
* [Update] 修改assets * [Update] 修复用户组页面权限 * [Update] 统一授权资产页面,修改apiUpdateAttr函数名称pull/2942/head
parent
e5bdceed58
commit
55b049c86a
|
@ -13,11 +13,11 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from rest_framework_bulk import BulkModelViewSet
|
||||
from rest_framework.pagination import LimitOffsetPagination
|
||||
from django.db.models import Count
|
||||
|
||||
from common.utils import get_logger
|
||||
from orgs.mixins import OrgBulkModelViewSet
|
||||
from ..hands import IsOrgAdmin
|
||||
from ..models import Label
|
||||
from .. import serializers
|
||||
|
@ -27,7 +27,7 @@ logger = get_logger(__file__)
|
|||
__all__ = ['LabelViewSet']
|
||||
|
||||
|
||||
class LabelViewSet(BulkModelViewSet):
|
||||
class LabelViewSet(OrgBulkModelViewSet):
|
||||
filter_fields = ("name", "value")
|
||||
search_fields = filter_fields
|
||||
permission_classes = (IsOrgAdmin,)
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Generated by Django 2.1.7 on 2019-07-11 12:18
|
||||
|
||||
import common.fields.model
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0034_auto_20190705_1348'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='adminuser',
|
||||
name='private_key',
|
||||
field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='authbook',
|
||||
name='private_key',
|
||||
field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gateway',
|
||||
name='private_key',
|
||||
field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='systemuser',
|
||||
name='private_key',
|
||||
field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
|
||||
),
|
||||
]
|
|
@ -28,7 +28,7 @@ class AssetUser(OrgModelMixin):
|
|||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||
username = models.CharField(max_length=32, blank=True, verbose_name=_('Username'), validators=[alphanumeric])
|
||||
password = fields.EncryptCharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
|
||||
private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
|
||||
private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'))
|
||||
public_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH public key'))
|
||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created"))
|
||||
|
|
|
@ -21,17 +21,14 @@ class AdminUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
|
|||
model = AdminUser
|
||||
fields = [
|
||||
'id', 'name', 'username', 'password', 'private_key', 'public_key',
|
||||
'comment', 'assets_amount',
|
||||
'date_created', 'date_updated', 'created_by',
|
||||
'comment', 'assets_amount', 'date_created', 'date_updated', 'created_by',
|
||||
]
|
||||
read_only_fields = ['date_created', 'date_updated', 'created_by', 'assets_amount']
|
||||
|
||||
extra_kwargs = {
|
||||
'password': {"write_only": True},
|
||||
'private_key': {"write_only": True},
|
||||
'public_key': {"write_only": True},
|
||||
'date_created': {'read_only': True},
|
||||
'date_updated': {'read_only': True},
|
||||
'created_by': {'read_only': True},
|
||||
'assets_amount': {'label': _('Asset')},
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ function showAuth() {
|
|||
var msg = "{% trans 'Get auth info error' %}";
|
||||
toastr.error(msg)
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
|
|
|
@ -141,7 +141,7 @@ $(document).ready(function(){
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
success: success,
|
||||
|
|
|
@ -235,7 +235,7 @@ function onRename(event, treeId, treeNode, isCancel){
|
|||
if (isCancel){
|
||||
return
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: url,
|
||||
body: JSON.stringify(data),
|
||||
method: "PATCH",
|
||||
|
@ -274,7 +274,7 @@ function onDrop(event, treeId, treeNodes, targetNode, moveType) {
|
|||
|
||||
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.meta.node.id);
|
||||
var body = {nodes: treeNodesIds};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: "PUT",
|
||||
body: JSON.stringify(body)
|
||||
|
|
|
@ -88,7 +88,7 @@ $(document).ready(function () {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
success: success,
|
||||
|
|
|
@ -131,7 +131,7 @@ function replaceNodeAssetsAdminUser(nodes) {
|
|||
// clear jumpserver.groups_selected
|
||||
jumpserver.nodes_selected = {};
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
|
|
@ -84,7 +84,7 @@ $(document).ready(function () {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
success: success,
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Protocol' %}</td>
|
||||
<td>{{ asset.protocols }}</td>
|
||||
<td><b>{{ asset.protocols }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Admin user' %}:</td>
|
||||
|
@ -267,7 +267,7 @@ function updateAssetNodes(nodes) {
|
|||
// clear jumpserver.groups_selected
|
||||
jumpserver.nodes_selected = {};
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -282,7 +282,7 @@ function refreshAssetHardware() {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
success: success,
|
||||
method: 'GET'
|
||||
|
@ -306,7 +306,7 @@ $(document).ready(function () {
|
|||
};
|
||||
var success = '{% trans "Update successfully!" %}';
|
||||
var status = $(".ibox-content > table > tbody > tr:nth-child(13) > td:last >b").text();
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success_message: success
|
||||
|
@ -360,7 +360,7 @@ $(document).ready(function () {
|
|||
window.open(url, '', 'width=800,height=600')
|
||||
};
|
||||
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
success: success
|
||||
|
|
|
@ -360,7 +360,7 @@ $(document).ready(function(){
|
|||
setTimeout( function () {
|
||||
window.location.reload();}, 500);
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
|
@ -377,7 +377,7 @@ $(document).ready(function(){
|
|||
setTimeout( function () {
|
||||
window.location.reload();}, 300);
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
|
@ -397,7 +397,7 @@ $(document).ready(function(){
|
|||
},function () {
|
||||
function success(data) {
|
||||
url = setUrlParam(the_url, 'spm', data.spm);
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url:url,
|
||||
method:'DELETE',
|
||||
success:refreshTag,
|
||||
|
@ -410,7 +410,7 @@ $(document).ready(function(){
|
|||
var msg = "{% trans 'Asset Deleting failed.' %}";
|
||||
swal("{% trans 'Asset Delete' %}", msg, "error");
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: "{% url 'api-common:resources-cache' %}",
|
||||
method:'POST',
|
||||
body:JSON.stringify(data),
|
||||
|
@ -428,7 +428,7 @@ $(document).ready(function(){
|
|||
var url = "{% url 'assets:asset-bulk-update' %}";
|
||||
location.href= setUrlParam(url, 'spm', data.spm);
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: "{% url 'api-common:resources-cache' %}",
|
||||
method:'POST',
|
||||
body:JSON.stringify(data),
|
||||
|
@ -452,7 +452,7 @@ $(document).ready(function(){
|
|||
asset_table.ajax.reload()
|
||||
};
|
||||
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
'url': '/api/assets/v1/nodes/' + current_node_id + '/assets/remove/',
|
||||
'method': 'PUT',
|
||||
'body': JSON.stringify(data),
|
||||
|
@ -500,7 +500,7 @@ $(document).ready(function(){
|
|||
url = "{% url 'api-assets:node-add-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
|
||||
}
|
||||
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
'url': url,
|
||||
'method': 'PUT',
|
||||
'body': JSON.stringify(data),
|
||||
|
@ -524,7 +524,7 @@ $(document).ready(function(){
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
|
@ -539,7 +539,7 @@ $(document).ready(function(){
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: "GET",
|
||||
success: success,
|
||||
|
|
|
@ -136,7 +136,7 @@ function updateCMDFilterSystemUsers(system_users) {
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'PATCH',
|
||||
|
|
|
@ -134,7 +134,7 @@ $(document).ready(function(){
|
|||
var data = $("#test_gateway_form").serializeObject();
|
||||
var uid = data.gateway_id;
|
||||
var the_url = '{% url "api-assets:test-gateway-connective" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: "POST",
|
||||
body: JSON.stringify({'port': parseInt(data.port)}),
|
||||
|
|
|
@ -146,7 +146,7 @@ function updateSystemUserNode(nodes) {
|
|||
// clear jumpserver.nodes_selected
|
||||
jumpserver.nodes_selected = {};
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -206,7 +206,7 @@ $(document).ready(function () {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
error: error,
|
||||
method: 'GET',
|
||||
|
@ -226,7 +226,7 @@ $(document).ready(function () {
|
|||
var error = function (data) {
|
||||
alert(data)
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
success: success,
|
||||
|
@ -243,7 +243,7 @@ $(document).ready(function () {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
error: error,
|
||||
method: 'GET',
|
||||
|
|
|
@ -212,7 +212,7 @@ function updateCommandFilters(command_filters) {
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -235,7 +235,7 @@ $(document).ready(function () {
|
|||
var body = {
|
||||
'auto_push': checked
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
@ -254,7 +254,7 @@ $(document).ready(function () {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
success: success,
|
||||
|
@ -268,7 +268,7 @@ $(document).ready(function () {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'GET',
|
||||
success: success,
|
||||
|
|
|
@ -182,7 +182,7 @@ $(document).ready(function(){
|
|||
swal("{% trans 'System Users Delete' %}", msg, "error");
|
||||
};
|
||||
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
|
||||
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
|
||||
requestApi({url: url_delete, method: 'DELETE', success: success, error: fail});
|
||||
$data_table.ajax.reload();
|
||||
jumpserver.checked = false;
|
||||
});
|
||||
|
|
|
@ -11,47 +11,7 @@
|
|||
{% block content %}
|
||||
<div class="wrapper wrapper-content">
|
||||
<div class="row">
|
||||
<div class="col-lg-3" id="split-left" style="padding-left: 3px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0;padding-left: 1px">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight" id="split-right">
|
||||
<div class="tree-toggle">
|
||||
<div class="btn btn-sm btn-primary tree-toggle-btn" onclick="toggle()">
|
||||
<i class="fa fa-angle-left fa-x" id="toggle-icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mail-box-header">
|
||||
<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="user_assets_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 'System users' %}</th>
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_granted_assets.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -62,121 +22,51 @@
|
|||
{% block custom_foot_js %}
|
||||
<script>
|
||||
var treeUrl = "{% url 'api-perms:my-nodes-as-tree' %}?&cache_policy=1";
|
||||
var zTree, asset_table, show=0;
|
||||
var inited = false;
|
||||
var url;
|
||||
|
||||
|
||||
function initTable() {
|
||||
if (inited){
|
||||
return
|
||||
} else {
|
||||
inited = true;
|
||||
}
|
||||
url = "{% url 'api-perms:my-assets' %}?cache_policy=1";
|
||||
var options = {
|
||||
ele: $('#user_assets_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
var detail_btn = '<a class="asset_detail" asset-id="rowData_id" data-toggle="modal" data-target="#user_asset_detail_modal" tabindex="0">'+ cellData +'</a>'
|
||||
$(td).html(detail_btn.replace("rowData_id", rowData.id));
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var users = [];
|
||||
$.each(cellData, function (id, data) {
|
||||
users.push(data.name);
|
||||
});
|
||||
$(td).html(users.join(', '))
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
var conn_btn = '<a href="{% url "luna-view" %}?login_to=' + cellData +'" class="btn btn-xs btn-primary">{% trans "Connect" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
|
||||
$(td).html(conn_btn)
|
||||
}}
|
||||
],
|
||||
ajax_url: url,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "system_users_granted", orderable: false},
|
||||
{data: "id", orderable: false}
|
||||
]
|
||||
};
|
||||
asset_table = jumpserver.initServerSideDataTable(options);
|
||||
return asset_table
|
||||
}
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
url = '{% url "api-perms:my-node-assets" node_id=DEFAULT_PK %}?cache_policy=1';
|
||||
var node_id = treeNode.meta.node.id;
|
||||
url = url.replace("{{ DEFAULT_PK }}", node_id);
|
||||
setCookie('node_selected', treeNode.id);
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true,
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected
|
||||
}
|
||||
};
|
||||
|
||||
var zNodes = [];
|
||||
$.get(treeUrl, function(data, status){
|
||||
zNodes = data;
|
||||
$.fn.zTree.init($("#assetTree"), setting, zNodes);
|
||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||
rootNodeAddDom(zTree, function () {
|
||||
treeUrl = treeUrl.replace('cache_policy=1', 'cache_policy=2');
|
||||
initTree();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
var assetTableUrl = "{% url 'api-perms:my-assets' %}?cache_policy=1";
|
||||
var selectUrl = '{% url "api-perms:my-node-assets" node_id=DEFAULT_PK %}?cache_policy=1';
|
||||
var showAssetHref = false; // Need input default true
|
||||
var actions = {
|
||||
targets: 4, createdCell: function (td, cellData) {
|
||||
var conn_btn = '<a href="{% url "luna-view" %}?login_to=' + cellData +
|
||||
'" class="btn btn-xs btn-primary">{% trans "Connect" %}</a>';
|
||||
$(td).html(conn_btn)
|
||||
}};
|
||||
$(document).ready(function () {
|
||||
initTree();
|
||||
initTable();
|
||||
}).on('click', '.labels li', function () {
|
||||
var val = $(this).text();
|
||||
$("#user_assets_table_filter input").val(val);
|
||||
asset_table.search(val).draw();
|
||||
assetTable.search(val).draw();
|
||||
})
|
||||
.on('click', '.asset_detail', function() {
|
||||
var data = asset_table.ajax.json();
|
||||
var asset_id = this.getAttribute("asset-id");
|
||||
.on('click', '.asset-detail', function(e) {
|
||||
e.preventDefault();
|
||||
var data = assetTable.ajax.json();
|
||||
var assetId = $(this).data("asset");
|
||||
var trs = '';
|
||||
var desc = {
|
||||
'hostname': "{% trans 'Hostname' %}",
|
||||
'ip': "{% trans 'IP' %}",
|
||||
'port': "{% trans 'Port' %}",
|
||||
'protocol': "{% trans 'Protocol' %}",
|
||||
'protocols': "{% trans 'Protocols' %}",
|
||||
'platform': "{% trans 'Platform' %}",
|
||||
'os': "{% trans 'OS' %}",
|
||||
'system_users_join': "{% trans 'System user' %}",
|
||||
'domain': "{% trans 'Domain' %}",
|
||||
'is_active': "{% trans 'Is active' %}",
|
||||
'comment': "{% trans 'Comment' %}"
|
||||
{#'date_joined': "{% trans 'Date joined' %}",#}
|
||||
};
|
||||
$.each(data.results, function(index, value){
|
||||
if(value.id === asset_id){
|
||||
var value;
|
||||
for (var i = 0; i < data.results.length; i++) {
|
||||
value = data.results[i];
|
||||
if(value.id === assetId){
|
||||
for(var i in desc){
|
||||
trs += "<tr class='no-borders-tr'>\n" +
|
||||
"<td>"+ desc[i] + ":</td>"+
|
||||
"<td><b>"+ (value[i] === null?'':value[i]) + "</b></td>\n" +
|
||||
"</tr>";
|
||||
}
|
||||
break
|
||||
}
|
||||
});
|
||||
};
|
||||
$('#asset_detail_tbody').html(trs)
|
||||
$('#user_asset_detail_modal').modal();
|
||||
});
|
||||
|
||||
function toggle() {
|
||||
|
@ -195,5 +85,4 @@ function toggle() {
|
|||
}
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -1,7 +1,8 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
import time
|
||||
from django.db.models import Prefetch
|
||||
from functools import reduce
|
||||
from django.db.models import Prefetch, Q
|
||||
|
||||
from common.utils import get_object_or_none, get_logger
|
||||
from common.struct import Stack
|
||||
|
@ -21,24 +22,34 @@ def get_system_user_by_id(id):
|
|||
return system_user
|
||||
|
||||
|
||||
class LabelFilter:
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super().filter_queryset(queryset)
|
||||
query_keys = self.request.query_params.keys()
|
||||
class LabelFilterMixin:
|
||||
def get_filter_labels_ids(self):
|
||||
query_params = self.request.query_params
|
||||
query_keys = query_params.keys()
|
||||
all_label_keys = Label.objects.values_list('name', flat=True)
|
||||
valid_keys = set(all_label_keys) & set(query_keys)
|
||||
labels_query = {}
|
||||
for key in valid_keys:
|
||||
labels_query[key] = self.request.query_params.get(key)
|
||||
|
||||
conditions = []
|
||||
for k, v in labels_query.items():
|
||||
query = {'labels__name': k, 'labels__value': v}
|
||||
conditions.append(query)
|
||||
if not valid_keys:
|
||||
return []
|
||||
|
||||
if conditions:
|
||||
for kwargs in conditions:
|
||||
queryset = queryset.filter(**kwargs)
|
||||
labels_query = [
|
||||
{"name": key, "value": query_params[key]}
|
||||
for key in valid_keys
|
||||
]
|
||||
args = [Q(**kwargs) for kwargs in labels_query]
|
||||
args = reduce(lambda x, y: x | y, args)
|
||||
labels_id = Label.objects.filter(args).values_list('id', flat=True)
|
||||
return labels_id
|
||||
|
||||
|
||||
class LabelFilter(LabelFilterMixin):
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super().filter_queryset(queryset)
|
||||
labels_ids = self.get_filter_labels_ids()
|
||||
if not labels_ids:
|
||||
return queryset
|
||||
for labels_id in labels_ids:
|
||||
queryset = queryset.filter(labels=labels_id)
|
||||
return queryset
|
||||
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ class UserAssetListView(PermissionsMixin, TemplateView):
|
|||
context = {
|
||||
'action': _('My assets'),
|
||||
'labels': Label.objects.all().order_by('name'),
|
||||
'system_users': SystemUser.objects.all(),
|
||||
'show_actions': True
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super().get_context_data(**kwargs)
|
||||
|
|
|
@ -38,7 +38,7 @@ $(document).ready(function () {
|
|||
var error = function () {
|
||||
$("#mfa_error").addClass("text-danger").html(codeError);
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: url,
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
|
|
|
@ -145,13 +145,13 @@ class NeedMFAVerify(permissions.BasePermission):
|
|||
return False
|
||||
|
||||
|
||||
class CanUpdateSuperUser(permissions.BasePermission):
|
||||
class CanUpdateDeleteSuperUser(permissions.BasePermission):
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if request.method in ['GET', 'OPTIONS']:
|
||||
return True
|
||||
if str(request.user.id) == str(obj.id):
|
||||
elif request.method == 'DELETE' and str(request.user.id) == str(obj.id):
|
||||
return False
|
||||
if request.user.is_superuser:
|
||||
elif request.user.is_superuser:
|
||||
return True
|
||||
if hasattr(obj, 'is_superuser') and obj.is_superuser:
|
||||
return False
|
||||
|
|
|
@ -255,7 +255,7 @@ function execute() {
|
|||
}
|
||||
}
|
||||
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: url,
|
||||
body: JSON.stringify(data),
|
||||
method: 'POST',
|
||||
|
|
|
@ -109,7 +109,7 @@ $(document).ready(function() {
|
|||
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
|
||||
window.open(url, '', 'width=800,height=600,left=400,top=400')
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
error: error,
|
||||
method: 'GET',
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
from functools import reduce
|
||||
from hashlib import md5
|
||||
from django.core.cache import cache
|
||||
from django.db.models import Q
|
||||
from django.conf import settings
|
||||
from rest_framework.views import Response
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
from common.utils import get_logger
|
||||
from assets.utils import LabelFilterMixin
|
||||
from ..utils import (
|
||||
AssetPermissionUtil
|
||||
)
|
||||
from .. import const
|
||||
from ..hands import Asset, Node, SystemUser, Label
|
||||
from .. import serializers
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
__all__ = ['UserPermissionCacheMixin', 'GrantAssetsMixin', 'NodesWithUngroupMixin']
|
||||
|
||||
|
||||
class UserPermissionCacheMixin:
|
||||
cache_policy = '0'
|
||||
RESP_CACHE_KEY = '_PERMISSION_RESPONSE_CACHE_V2_{}'
|
||||
CACHE_TIME = settings.ASSETS_PERM_CACHE_TIME
|
||||
_object = None
|
||||
|
||||
def get_object(self):
|
||||
return None
|
||||
|
||||
# 内部使用可控制缓存
|
||||
def _get_object(self):
|
||||
if not self._object:
|
||||
self._object = self.get_object()
|
||||
return self._object
|
||||
|
||||
def get_object_id(self):
|
||||
obj = self._get_object()
|
||||
if obj:
|
||||
return str(obj.id)
|
||||
return None
|
||||
|
||||
def get_request_md5(self):
|
||||
path = self.request.path
|
||||
query = {k: v for k, v in self.request.GET.items()}
|
||||
query.pop("_", None)
|
||||
query = "&".join(["{}={}".format(k, v) for k, v in query.items()])
|
||||
full_path = "{}?{}".format(path, query)
|
||||
return md5(full_path.encode()).hexdigest()
|
||||
|
||||
def get_meta_cache_id(self):
|
||||
obj = self._get_object()
|
||||
util = AssetPermissionUtil(obj, cache_policy=self.cache_policy)
|
||||
meta_cache_id = util.cache_meta.get('id')
|
||||
return meta_cache_id
|
||||
|
||||
def get_response_cache_id(self):
|
||||
obj_id = self.get_object_id()
|
||||
request_md5 = self.get_request_md5()
|
||||
meta_cache_id = self.get_meta_cache_id()
|
||||
resp_cache_id = '{}_{}_{}'.format(obj_id, request_md5, meta_cache_id)
|
||||
return resp_cache_id
|
||||
|
||||
def get_response_from_cache(self):
|
||||
# 没有数据缓冲
|
||||
meta_cache_id = self.get_meta_cache_id()
|
||||
if not meta_cache_id:
|
||||
logger.debug("Not get meta id: {}".format(meta_cache_id))
|
||||
return None
|
||||
# 从响应缓冲里获取响应
|
||||
key = self.get_response_key()
|
||||
data = cache.get(key)
|
||||
if not data:
|
||||
logger.debug("Not get response from cache: {}".format(key))
|
||||
return None
|
||||
logger.debug("Get user permission from cache: {}".format(self.get_object()))
|
||||
response = Response(data)
|
||||
return response
|
||||
|
||||
def expire_response_cache(self):
|
||||
obj_id = self.get_object_id()
|
||||
expire_cache_id = '{}_{}'.format(obj_id, '*')
|
||||
key = self.RESP_CACHE_KEY.format(expire_cache_id)
|
||||
cache.delete_pattern(key)
|
||||
|
||||
def get_response_key(self):
|
||||
resp_cache_id = self.get_response_cache_id()
|
||||
key = self.RESP_CACHE_KEY.format(resp_cache_id)
|
||||
return key
|
||||
|
||||
def set_response_to_cache(self, response):
|
||||
key = self.get_response_key()
|
||||
cache.set(key, response.data, self.CACHE_TIME)
|
||||
logger.debug("Set response to cache: {}".format(key))
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.cache_policy = request.GET.get('cache_policy', '0')
|
||||
|
||||
obj = self._get_object()
|
||||
if obj is None:
|
||||
logger.debug("Not get response from cache: obj is none")
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
if AssetPermissionUtil.is_not_using_cache(self.cache_policy):
|
||||
logger.debug("Not get resp from cache: {}".format(self.cache_policy))
|
||||
return super().get(request, *args, **kwargs)
|
||||
elif AssetPermissionUtil.is_refresh_cache(self.cache_policy):
|
||||
logger.debug("Not get resp from cache: {}".format(self.cache_policy))
|
||||
self.expire_response_cache()
|
||||
|
||||
logger.debug("Try get response from cache")
|
||||
resp = self.get_response_from_cache()
|
||||
if not resp:
|
||||
resp = super().get(request, *args, **kwargs)
|
||||
self.set_response_to_cache(resp)
|
||||
return resp
|
||||
|
||||
|
||||
class NodesWithUngroupMixin:
|
||||
util = None
|
||||
|
||||
@staticmethod
|
||||
def get_ungrouped_node(ungroup_key):
|
||||
return Node(key=ungroup_key, id=const.UNGROUPED_NODE_ID,
|
||||
value=_("ungrouped"))
|
||||
|
||||
@staticmethod
|
||||
def get_empty_node():
|
||||
return Node(key=const.EMPTY_NODE_KEY, id=const.EMPTY_NODE_ID,
|
||||
value=_("empty"))
|
||||
|
||||
def add_ungrouped_nodes(self, node_map, node_keys):
|
||||
ungroup_key = '1:-1'
|
||||
for key in node_keys:
|
||||
if key.endswith('-1'):
|
||||
ungroup_key = key
|
||||
break
|
||||
ungroup_node = self.get_ungrouped_node(ungroup_key)
|
||||
empty_node = self.get_empty_node()
|
||||
node_map[ungroup_key] = ungroup_node
|
||||
node_map[const.EMPTY_NODE_KEY] = empty_node
|
||||
|
||||
|
||||
class GrantAssetsMixin(LabelFilterMixin):
|
||||
serializer_class = serializers.AssetGrantedSerializer
|
||||
|
||||
def get_serializer_queryset(self, queryset):
|
||||
assets_ids = []
|
||||
system_users_ids = set()
|
||||
for asset in queryset:
|
||||
assets_ids.append(asset["id"])
|
||||
system_users_ids.update(set(asset["system_users"]))
|
||||
assets = Asset.objects.filter(id__in=assets_ids).only(
|
||||
*self.serializer_class.Meta.only_fields
|
||||
)
|
||||
assets_map = {asset.id: asset for asset in assets}
|
||||
system_users = SystemUser.objects.filter(id__in=system_users_ids).only(
|
||||
*self.serializer_class.system_users_only_fields
|
||||
)
|
||||
system_users_map = {s.id: s for s in system_users}
|
||||
data = []
|
||||
for item in queryset:
|
||||
i = item["id"]
|
||||
asset = assets_map.get(i)
|
||||
if not asset:
|
||||
continue
|
||||
|
||||
_system_users = item["system_users"]
|
||||
system_users_granted = []
|
||||
for sid, action in _system_users.items():
|
||||
system_user = system_users_map.get(sid)
|
||||
if not system_user:
|
||||
continue
|
||||
system_user.actions = action
|
||||
system_users_granted.append(system_user)
|
||||
asset.system_users_granted = system_users_granted
|
||||
data.append(asset)
|
||||
return data
|
||||
|
||||
def get_serializer(self, queryset_list, many=True):
|
||||
data = self.get_serializer_queryset(queryset_list)
|
||||
return super().get_serializer(data, many=True)
|
||||
|
||||
def search_queryset(self, assets_items):
|
||||
search = self.request.query_params.get("search")
|
||||
if not search:
|
||||
return assets_items
|
||||
assets_map = {asset['id']: asset for asset in assets_items}
|
||||
assets_ids = set(assets_map.keys())
|
||||
assets_ids_search = Asset.objects.filter(id__in=assets_ids).filter(
|
||||
Q(hostname__icontains=search) | Q(ip__icontains=search)
|
||||
).values_list('id', flat=True)
|
||||
return [assets_map.get(asset_id) for asset_id in assets_ids_search]
|
||||
|
||||
def filter_queryset_by_label(self, assets_items):
|
||||
labels_id = self.get_filter_labels_ids()
|
||||
if not labels_id:
|
||||
return assets_items
|
||||
|
||||
assets_map = {asset['id']: asset for asset in assets_items}
|
||||
assets_matched = Asset.objects.filter(id__in=assets_map.keys())
|
||||
for label_id in labels_id:
|
||||
assets_matched = assets_matched.filter(labels=label_id)
|
||||
assets_ids_matched = assets_matched.values_list('id', flat=True)
|
||||
return [assets_map.get(asset_id) for asset_id in assets_ids_matched]
|
||||
|
||||
def sort_queryset(self, assets_items):
|
||||
order_by = self.request.query_params.get('order', 'hostname')
|
||||
|
||||
if order_by not in ['hostname', '-hostname', 'ip', '-ip']:
|
||||
order_by = 'hostname'
|
||||
assets_map = {asset['id']: asset for asset in assets_items}
|
||||
assets_ids_search = Asset.objects.filter(id__in=assets_map.keys())\
|
||||
.order_by(order_by)\
|
||||
.values_list('id', flat=True)
|
||||
return [assets_map.get(asset_id) for asset_id in assets_ids_search]
|
||||
|
||||
def filter_queryset(self, assets_items):
|
||||
assets_items = self.search_queryset(assets_items)
|
||||
assets_items = self.filter_queryset_by_label(assets_items)
|
||||
assets_items = self.sort_queryset(assets_items)
|
||||
return assets_items
|
|
@ -2,23 +2,21 @@
|
|||
#
|
||||
|
||||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework.generics import (
|
||||
ListAPIView, get_object_or_404,
|
||||
)
|
||||
|
||||
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
|
||||
from ..hands import UserGroup
|
||||
from .. import serializers, const
|
||||
from .. import serializers
|
||||
|
||||
from .user_permission import (
|
||||
UserGrantedAssetsApi, UserGrantedNodesApi, UserGrantedNodesWithAssetsApi,
|
||||
UserGrantedNodesWithAssetsAsTreeApi, UserGrantedNodeAssetsApi,
|
||||
UserGrantedNodesAsTreeApi,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi',
|
||||
'UserGroupGrantedNodesWithAssetsApi', 'UserGroupGrantedNodeAssetsApi',
|
||||
'UserGroupGrantedNodesWithAssetsAsTreeApi',
|
||||
'UserGroupGrantedNodesWithAssetsAsTreeApi', 'UserGroupGrantedNodesAsTreeApi',
|
||||
]
|
||||
|
||||
|
||||
|
@ -36,6 +34,13 @@ class UserGroupGrantedNodesApi(UserGrantedNodesApi):
|
|||
return user_group
|
||||
|
||||
|
||||
class UserGroupGrantedNodesAsTreeApi(UserGrantedNodesAsTreeApi):
|
||||
def get_object(self):
|
||||
user_group_id = self.kwargs.get('pk', '')
|
||||
user_group = get_object_or_404(UserGroup, id=user_group_id)
|
||||
return user_group
|
||||
|
||||
|
||||
class UserGroupGrantedNodesWithAssetsApi(UserGrantedNodesWithAssetsApi):
|
||||
permission_classes = (IsOrgAdmin,)
|
||||
serializer_class = serializers.NodeGrantedSerializer
|
||||
|
|
|
@ -2,25 +2,23 @@
|
|||
#
|
||||
import time
|
||||
import traceback
|
||||
from functools import reduce
|
||||
import uuid
|
||||
from hashlib import md5
|
||||
from django.core.cache import cache
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
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, RetrieveAPIView
|
||||
)
|
||||
from django.utils.translation import ugettext as _
|
||||
from rest_framework.pagination import LimitOffsetPagination
|
||||
|
||||
from common.permissions import IsValidUser, IsOrgAdminOrAppUser
|
||||
from common.tree import TreeNodeSerializer
|
||||
from common.utils import get_logger, get_object_or_none
|
||||
from common.utils import get_logger
|
||||
from ..utils import (
|
||||
AssetPermissionUtil, ParserNode,
|
||||
)
|
||||
from .mixin import UserPermissionCacheMixin, GrantAssetsMixin, NodesWithUngroupMixin
|
||||
from .. import const
|
||||
from ..hands import User, Asset, Node, SystemUser, NodeSerializer
|
||||
from .. import serializers
|
||||
|
@ -37,153 +35,6 @@ __all__ = [
|
|||
]
|
||||
|
||||
|
||||
class UserPermissionCacheMixin:
|
||||
cache_policy = '0'
|
||||
RESP_CACHE_KEY = '_PERMISSION_RESPONSE_CACHE_V2_{}'
|
||||
CACHE_TIME = settings.ASSETS_PERM_CACHE_TIME
|
||||
_object = None
|
||||
|
||||
def get_object(self):
|
||||
return None
|
||||
|
||||
# 内部使用可控制缓存
|
||||
def _get_object(self):
|
||||
if not self._object:
|
||||
self._object = self.get_object()
|
||||
return self._object
|
||||
|
||||
def get_object_id(self):
|
||||
obj = self._get_object()
|
||||
if obj:
|
||||
return str(obj.id)
|
||||
return None
|
||||
|
||||
def get_request_md5(self):
|
||||
path = self.request.path
|
||||
query = {k: v for k, v in self.request.GET.items()}
|
||||
query.pop("_", None)
|
||||
query = "&".join(["{}={}".format(k, v) for k, v in query.items()])
|
||||
full_path = "{}?{}".format(path, query)
|
||||
return md5(full_path.encode()).hexdigest()
|
||||
|
||||
def get_meta_cache_id(self):
|
||||
obj = self._get_object()
|
||||
util = AssetPermissionUtil(obj, cache_policy=self.cache_policy)
|
||||
meta_cache_id = util.cache_meta.get('id')
|
||||
return meta_cache_id
|
||||
|
||||
def get_response_cache_id(self):
|
||||
obj_id = self.get_object_id()
|
||||
request_md5 = self.get_request_md5()
|
||||
meta_cache_id = self.get_meta_cache_id()
|
||||
resp_cache_id = '{}_{}_{}'.format(obj_id, request_md5, meta_cache_id)
|
||||
return resp_cache_id
|
||||
|
||||
def get_response_from_cache(self):
|
||||
# 没有数据缓冲
|
||||
meta_cache_id = self.get_meta_cache_id()
|
||||
if not meta_cache_id:
|
||||
logger.debug("Not get meta id: {}".format(meta_cache_id))
|
||||
return None
|
||||
# 从响应缓冲里获取响应
|
||||
key = self.get_response_key()
|
||||
data = cache.get(key)
|
||||
if not data:
|
||||
logger.debug("Not get response from cache: {}".format(key))
|
||||
return None
|
||||
logger.debug("Get user permission from cache: {}".format(self.get_object()))
|
||||
response = Response(data)
|
||||
return response
|
||||
|
||||
def expire_response_cache(self):
|
||||
obj_id = self.get_object_id()
|
||||
expire_cache_id = '{}_{}'.format(obj_id, '*')
|
||||
key = self.RESP_CACHE_KEY.format(expire_cache_id)
|
||||
cache.delete_pattern(key)
|
||||
|
||||
def get_response_key(self):
|
||||
resp_cache_id = self.get_response_cache_id()
|
||||
key = self.RESP_CACHE_KEY.format(resp_cache_id)
|
||||
return key
|
||||
|
||||
def set_response_to_cache(self, response):
|
||||
key = self.get_response_key()
|
||||
cache.set(key, response.data, self.CACHE_TIME)
|
||||
logger.debug("Set response to cache: {}".format(key))
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.cache_policy = request.GET.get('cache_policy', '0')
|
||||
|
||||
obj = self._get_object()
|
||||
if obj is None:
|
||||
logger.debug("Not get response from cache: obj is none")
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
if AssetPermissionUtil.is_not_using_cache(self.cache_policy):
|
||||
logger.debug("Not get resp from cache: {}".format(self.cache_policy))
|
||||
return super().get(request, *args, **kwargs)
|
||||
elif AssetPermissionUtil.is_refresh_cache(self.cache_policy):
|
||||
logger.debug("Not get resp from cache: {}".format(self.cache_policy))
|
||||
self.expire_response_cache()
|
||||
|
||||
logger.debug("Try get response from cache")
|
||||
resp = self.get_response_from_cache()
|
||||
if not resp:
|
||||
resp = super().get(request, *args, **kwargs)
|
||||
self.set_response_to_cache(resp)
|
||||
return resp
|
||||
|
||||
|
||||
class GrantAssetsMixin:
|
||||
serializer_class = serializers.AssetGrantedSerializer
|
||||
|
||||
def get_serializer(self, queryset, many=True):
|
||||
assets_ids = []
|
||||
system_users_ids = set()
|
||||
for asset in queryset:
|
||||
assets_ids.append(asset["id"])
|
||||
system_users_ids.update(set(asset["system_users"]))
|
||||
assets = Asset.objects.filter(id__in=assets_ids).only(
|
||||
*self.serializer_class.Meta.only_fields
|
||||
)
|
||||
assets_map = {asset.id: asset for asset in assets}
|
||||
system_users = SystemUser.objects.filter(id__in=system_users_ids).only(
|
||||
*self.serializer_class.system_users_only_fields
|
||||
)
|
||||
system_users_map = {s.id: s for s in system_users}
|
||||
data = []
|
||||
for item in queryset:
|
||||
i = item["id"]
|
||||
asset = assets_map.get(i)
|
||||
if not asset:
|
||||
continue
|
||||
|
||||
_system_users = item["system_users"]
|
||||
system_users_granted = []
|
||||
for sid, action in _system_users.items():
|
||||
system_user = system_users_map.get(sid)
|
||||
if not system_user:
|
||||
continue
|
||||
system_user.actions = action
|
||||
system_users_granted.append(system_user)
|
||||
asset.system_users_granted = system_users_granted
|
||||
data.append(asset)
|
||||
return super().get_serializer(data, many=True)
|
||||
|
||||
def search_queryset(self, assets):
|
||||
search = self.request.query_params.get("search")
|
||||
if not search:
|
||||
return assets
|
||||
|
||||
assets_map = {asset['id']: asset for asset in assets}
|
||||
assets_ids = set(assets_map.keys())
|
||||
assets_ids_search = Asset.objects.filter(id__in=assets_ids).filter(
|
||||
Q(hostname__icontains=search) | Q(ip__icontains=search)
|
||||
).values_list('id', flat=True)
|
||||
assets_ids &= set(assets_ids_search)
|
||||
return [assets_map.get(asset_id) for asset_id in assets_ids]
|
||||
|
||||
|
||||
class UserGrantedAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView):
|
||||
"""
|
||||
用户授权的所有资产
|
||||
|
@ -203,7 +54,6 @@ class UserGrantedAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIVi
|
|||
user = self.get_object()
|
||||
util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
|
||||
queryset = util.get_assets()
|
||||
queryset = self.search_queryset(queryset)
|
||||
return queryset
|
||||
|
||||
def get_permissions(self):
|
||||
|
@ -212,29 +62,52 @@ class UserGrantedAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIVi
|
|||
return super().get_permissions()
|
||||
|
||||
|
||||
class NodesWithUngroupMixin:
|
||||
util = None
|
||||
class UserGrantedNodeAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView):
|
||||
"""
|
||||
查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产
|
||||
"""
|
||||
permission_classes = (IsOrgAdminOrAppUser,)
|
||||
pagination_class = LimitOffsetPagination
|
||||
|
||||
@staticmethod
|
||||
def get_ungrouped_node(ungroup_key):
|
||||
return Node(key=ungroup_key, id=const.UNGROUPED_NODE_ID,
|
||||
value=_("ungrouped"))
|
||||
def get_object(self):
|
||||
user_id = self.kwargs.get('pk', '')
|
||||
|
||||
@staticmethod
|
||||
def get_empty_node():
|
||||
return Node(key=const.EMPTY_NODE_KEY, id=const.EMPTY_NODE_ID,
|
||||
value=_("empty"))
|
||||
if user_id:
|
||||
user = get_object_or_404(User, id=user_id)
|
||||
else:
|
||||
user = self.request.user
|
||||
return user
|
||||
|
||||
def add_ungrouped_nodes(self, node_map, node_keys):
|
||||
ungroup_key = '1:-1'
|
||||
for key in node_keys:
|
||||
if key.endswith('-1'):
|
||||
ungroup_key = key
|
||||
def get_node_key(self):
|
||||
node_id = self.kwargs.get('node_id')
|
||||
if str(node_id) == const.UNGROUPED_NODE_ID:
|
||||
key = self.util.tree.ungrouped_key
|
||||
elif str(node_id) == const.EMPTY_NODE_ID:
|
||||
key = const.EMPTY_NODE_KEY
|
||||
else:
|
||||
node = get_object_or_404(Node, id=node_id)
|
||||
key = node.key
|
||||
return key
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.get_object()
|
||||
self.util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
|
||||
key = self.get_node_key()
|
||||
nodes_items = self.util.get_nodes_with_assets()
|
||||
assets_system_users = {}
|
||||
for item in nodes_items:
|
||||
if item["key"] == key:
|
||||
assets_system_users = item["assets"]
|
||||
break
|
||||
ungroup_node = self.get_ungrouped_node(ungroup_key)
|
||||
empty_node = self.get_empty_node()
|
||||
node_map[ungroup_key] = ungroup_node
|
||||
node_map[const.EMPTY_NODE_KEY] = empty_node
|
||||
assets = []
|
||||
for asset_id, system_users in assets_system_users.items():
|
||||
assets.append({"id": asset_id, "system_users": system_users})
|
||||
return assets
|
||||
|
||||
def get_permissions(self):
|
||||
if self.kwargs.get('pk') is None:
|
||||
self.permission_classes = (IsValidUser,)
|
||||
return super().get_permissions()
|
||||
|
||||
|
||||
class UserGrantedNodesApi(UserPermissionCacheMixin, NodesWithUngroupMixin, ListAPIView):
|
||||
|
@ -435,55 +308,6 @@ class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodesWithAssetsApi):
|
|||
return self.serializer_class(queryset, many=True)
|
||||
|
||||
|
||||
class UserGrantedNodeAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView):
|
||||
"""
|
||||
查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产
|
||||
"""
|
||||
permission_classes = (IsOrgAdminOrAppUser,)
|
||||
pagination_class = LimitOffsetPagination
|
||||
|
||||
def get_object(self):
|
||||
user_id = self.kwargs.get('pk', '')
|
||||
|
||||
if user_id:
|
||||
user = get_object_or_404(User, id=user_id)
|
||||
else:
|
||||
user = self.request.user
|
||||
return user
|
||||
|
||||
def get_node_key(self):
|
||||
node_id = self.kwargs.get('node_id')
|
||||
if str(node_id) == const.UNGROUPED_NODE_ID:
|
||||
key = self.util.tree.ungrouped_key
|
||||
elif str(node_id) == const.EMPTY_NODE_ID:
|
||||
key = const.EMPTY_NODE_KEY
|
||||
else:
|
||||
node = get_object_or_404(Node, id=node_id)
|
||||
key = node.key
|
||||
return key
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.get_object()
|
||||
self.util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
|
||||
key = self.get_node_key()
|
||||
nodes_items = self.util.get_nodes_with_assets()
|
||||
assets_system_users = {}
|
||||
for item in nodes_items:
|
||||
if item["key"] == key:
|
||||
assets_system_users = item["assets"]
|
||||
break
|
||||
assets = []
|
||||
for asset_id, system_users in assets_system_users.items():
|
||||
assets.append({"id": asset_id, "system_users": system_users})
|
||||
assets = self.search_queryset(assets)
|
||||
return assets
|
||||
|
||||
def get_permissions(self):
|
||||
if self.kwargs.get('pk') is None:
|
||||
self.permission_classes = (IsValidUser,)
|
||||
return super().get_permissions()
|
||||
|
||||
|
||||
class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView):
|
||||
permission_classes = (IsOrgAdminOrAppUser,)
|
||||
|
||||
|
@ -522,16 +346,12 @@ class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, RetrieveAPIView
|
|||
system_id = self.request.query_params.get('system_user_id', '')
|
||||
|
||||
user = get_object_or_404(User, id=user_id)
|
||||
asset = get_object_or_404(Asset, id=asset_id)
|
||||
su = get_object_or_404(SystemUser, id=system_id)
|
||||
|
||||
util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
|
||||
granted_assets = util.get_assets()
|
||||
granted_system_users = granted_assets.get(asset, {})
|
||||
|
||||
_object = {}
|
||||
if su not in granted_system_users:
|
||||
_object['actions'] = 0
|
||||
else:
|
||||
_object['actions'] = granted_system_users[su]
|
||||
return _object
|
||||
assets = util.get_assets()
|
||||
actions = 0
|
||||
for asset in assets:
|
||||
if asset_id == asset["id"]:
|
||||
actions = asset["system_users"].get(system_id, 0)
|
||||
break
|
||||
return {"actions": actions}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
|
||||
from users.models import User, UserGroup
|
||||
from assets.models import Asset, SystemUser, Node
|
||||
from assets.models import Asset, SystemUser, Node, Label
|
||||
from assets.serializers import NodeSerializer
|
||||
from applications.serializers import RemoteAppSerializer
|
||||
from applications.models import RemoteApp
|
||||
|
|
|
@ -145,7 +145,7 @@ function addAssets(assets) {
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -160,7 +160,7 @@ function removeAssets(assets) {
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -172,7 +172,7 @@ function updateNodes(nodes, success) {
|
|||
var body = {
|
||||
nodes: nodes
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
|
|
@ -187,7 +187,7 @@ function updateSystemUser(system_users) {
|
|||
var body = {
|
||||
system_users: Object.assign([], system_users)
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
@ -247,7 +247,7 @@ $(document).ready(function () {
|
|||
var body = {
|
||||
'is_active': checked
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
|
|
@ -160,7 +160,7 @@ function addUsers(users) {
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -175,7 +175,7 @@ function removeUser(users) {
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -187,7 +187,7 @@ function updateGroup(groups) {
|
|||
var body = {
|
||||
user_groups: groups
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
|
|
@ -160,7 +160,7 @@ $(document).ready(function () {
|
|||
var body = {
|
||||
'is_active': checked
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
|
|
@ -120,7 +120,7 @@
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -134,7 +134,7 @@
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -172,7 +172,7 @@
|
|||
var success = function(data) {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -183,7 +183,7 @@
|
|||
var body = {
|
||||
user_groups: groups
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
|
|
|
@ -39,9 +39,10 @@ asset_permission_urlpatterns = [
|
|||
|
||||
# 查询某个用户组授权的资产和资产组
|
||||
path('user-groups/<uuid:pk>/assets/', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'),
|
||||
path('user-groups/<uuid:pk>/nodes/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'),
|
||||
path('user-groups/<uuid:pk>/nodes-assets/', api.UserGroupGrantedNodesWithAssetsApi.as_view(), name='user-group-nodes-assets'),
|
||||
path('user-groups/<uuid:pk>/nodes/tree/', api.UserGroupGrantedNodesApi.as_view(), name='user-group-nodes'),
|
||||
path('user-groups/<uuid:pk>/nodes/', api.UserGroupGrantedNodesAsTreeApi.as_view(), name='user-group-nodes-as-tree'),
|
||||
path('user-groups/<uuid:pk>/nodes-assets/tree/', api.UserGroupGrantedNodesWithAssetsAsTreeApi.as_view(), name='user-group-nodes-assets-as-tree'),
|
||||
path('user-groups/<uuid:pk>/nodes-assets/', api.UserGroupGrantedNodesWithAssetsApi.as_view(), name='user-group-nodes-assets'),
|
||||
path('user-groups/<uuid:pk>/nodes/<uuid:node_id>/assets/', api.UserGroupGrantedNodeAssetsApi.as_view(), name='user-group-node-assets'),
|
||||
|
||||
# 用户和资产授权变更
|
||||
|
|
|
@ -96,7 +96,7 @@ $(document).ready(function () {
|
|||
function success(message) {
|
||||
toastr.success(message.msg)
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(data),
|
||||
method: "POST",
|
||||
|
|
|
@ -100,7 +100,7 @@ $(document).ready(function () {
|
|||
function success(message) {
|
||||
toastr.success(message.msg)
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(data),
|
||||
method: "POST",
|
||||
|
@ -127,7 +127,7 @@ $(document).ready(function () {
|
|||
function success(message) {
|
||||
toastr.success(message.msg)
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify({'username_list':username_list}),
|
||||
method: "POST",
|
||||
|
|
|
@ -256,7 +256,7 @@ function formSubmit(props) {
|
|||
})
|
||||
}
|
||||
|
||||
function APIUpdateAttr(props) {
|
||||
function requestApi(props) {
|
||||
// props = {url: .., body: , success: , error: , method: ,}
|
||||
props = props || {};
|
||||
var user_success_message = props.success_message;
|
||||
|
@ -328,7 +328,7 @@ function objectDelete(obj, name, url, redirectTo) {
|
|||
// swal("错误", "删除"+"[ "+name+" ]"+"遇到错误", "error");
|
||||
swal(gettext('Error'), "[ "+name+" ]" + gettext("Being used by the asset, please unbind the asset first."), "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
|
@ -369,7 +369,7 @@ function orgDelete(obj, name, url, redirectTo){
|
|||
swal(gettext("Error"), " [ "+ name + " ] " + gettext("Do not perform this operation under this organization. Try again after switching to another organization"), "error");
|
||||
}
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
|
@ -1109,7 +1109,19 @@ function objectAttrsIsBool(obj, attrs) {
|
|||
})
|
||||
}
|
||||
|
||||
function cleanDate(d) {
|
||||
for (var i=0; i<2; i++) {
|
||||
if (isNaN(Date.parse(d))) {
|
||||
d = d.split('+')[0].trimRight();
|
||||
} else {
|
||||
return d
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function formatDateAsCN(d) {
|
||||
d = cleanDate(d);
|
||||
var date = new Date(d);
|
||||
var date_s = date.toLocaleString(navigator.language, {hour12: false});
|
||||
return date_s.split("/").join('-')
|
||||
|
@ -1138,6 +1150,8 @@ function getTimeUnits(u) {
|
|||
}
|
||||
|
||||
function timeOffset(a, b) {
|
||||
a = cleanDate(a);
|
||||
b = cleanDate(b);
|
||||
var start = new Date(a);
|
||||
var end = new Date(b);
|
||||
var offset = (end - start)/1000;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -132,7 +132,7 @@
|
|||
}, 300)
|
||||
}
|
||||
var the_url = "{% url 'api-terminal:tasks-list' %}";
|
||||
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
||||
requestApi({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
|
||||
}
|
||||
$(document).ready(function () {
|
||||
$('.footable').footable();
|
||||
|
|
|
@ -90,7 +90,7 @@ function terminateSession(data) {
|
|||
}
|
||||
var success_message = '{% trans "Terminate task send, waiting ..." %}';
|
||||
var the_url = "{% url 'api-terminal:kill-session' %}";
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
|
@ -174,7 +174,7 @@ function finishedSession(data) {
|
|||
var success = function() {
|
||||
location.reload();
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
|
|
|
@ -14,7 +14,7 @@ from rest_framework.pagination import LimitOffsetPagination
|
|||
|
||||
from common.permissions import (
|
||||
IsOrgAdmin, IsCurrentUserOrReadOnly, IsOrgAdminOrAppUser,
|
||||
CanUpdateSuperUser,
|
||||
CanUpdateDeleteSuperUser,
|
||||
)
|
||||
from common.mixins import IDInCacheFilterMixin
|
||||
from common.utils import get_logger
|
||||
|
@ -38,7 +38,7 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
|
|||
search_fields = filter_fields
|
||||
queryset = User.objects.exclude(role=User.ROLE_APP)
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = (IsOrgAdmin, CanUpdateSuperUser)
|
||||
permission_classes = (IsOrgAdmin, CanUpdateDeleteSuperUser)
|
||||
pagination_class = LimitOffsetPagination
|
||||
|
||||
def send_created_signal(self, users):
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
{% load i18n %}
|
||||
<div class="col-lg-3" style="padding-left: 0px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight">
|
||||
<div class="mail-box-header">
|
||||
<div class="btn-group" style="float: right">
|
||||
<button data-toggle="dropdown" class="btn btn-default btn-sm labels dropdown-toggle">{% trans 'Label' %} <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu labels-menu">
|
||||
</ul>
|
||||
</div>
|
||||
<table class="table table-striped table-bordered table-hover" id="user_assets_table" >
|
||||
<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 'System user' %}</th>
|
||||
{% if show_actions %}
|
||||
<th class="text-center">{% trans 'Action' %}</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
var zTree;
|
||||
var inited = false;
|
||||
var url;
|
||||
var assetTable;
|
||||
var treeUrl = "NeedInput";
|
||||
var assetTableUrl = 'NeedInput';
|
||||
var selectUrl = 'NeedInput';
|
||||
var showAssetHref = true; // Need input default true
|
||||
var actions = {};
|
||||
var labels = '';
|
||||
var requesting = false;
|
||||
|
||||
function initTable() {
|
||||
if (inited){
|
||||
return assetTable
|
||||
} else {
|
||||
inited = true;
|
||||
}
|
||||
var options = {
|
||||
ele: $('#user_assets_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
cellData = htmlEscape(cellData);
|
||||
var assetDetailUrl = '{% url 'assets:asset-detail' pk=DEFAULT_PK %}'
|
||||
.replace("{{ DEFAULT_PK }}", rowData.id);
|
||||
var detailBtn = '<a href="assetDetailUrl" class="asset-detail" data-asset="assetId">' + cellData + '</a>';
|
||||
if (showAssetHref) {
|
||||
cellData = detailBtn.replace("assetDetailUrl", assetDetailUrl);
|
||||
} else {
|
||||
detailBtn = detailBtn.replace("assetId", rowData.id);
|
||||
cellData = detailBtn.replace("assetDetailUrl", "");
|
||||
}
|
||||
$(td).html(cellData);
|
||||
}},
|
||||
{targets: 3, createdCell: function (td, cellData) {
|
||||
var users = [];
|
||||
$.each(cellData, function (id, data) {
|
||||
var name = htmlEscape(data.name);
|
||||
users.push(name);
|
||||
});
|
||||
$(td).html(users.join(', '))
|
||||
}},
|
||||
],
|
||||
ajax_url: assetTableUrl,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "system_users_granted", orderable: false},
|
||||
{% if show_actions %}
|
||||
{data: "id", orderable: false}
|
||||
{% endif %}
|
||||
]
|
||||
};
|
||||
{% if show_actions %}
|
||||
options.columnDefs.push(actions);
|
||||
{% endif %}
|
||||
assetTable = jumpserver.initServerSideDataTable(options);
|
||||
return assetTable
|
||||
}
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
var node_id = treeNode.meta.node.id;
|
||||
url = selectUrl.replace("{{ DEFAULT_PK }}", node_id);
|
||||
assetTable.ajax.url(url);
|
||||
assetTable.ajax.reload();
|
||||
}
|
||||
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected
|
||||
}
|
||||
};
|
||||
|
||||
$.get(treeUrl, function(data, status) {
|
||||
$.fn.zTree.init($("#assetTree"), setting, data);
|
||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||
rootNodeAddDom(zTree, function () {
|
||||
treeUrl = treeUrl.replace('cache_policy=1', 'cache_policy=2');
|
||||
initTree();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadLabels() {
|
||||
var labelListUrl = '{% url "api-assets:label-list" %}';
|
||||
var label = '<li><a style="font-weight: bolder">labelName:labelValue</a></li>';
|
||||
if (requesting) {
|
||||
return
|
||||
}
|
||||
if (!labels) {
|
||||
var data = {
|
||||
url: labelListUrl,
|
||||
method: "GET",
|
||||
success: function (data) {
|
||||
data.forEach(function (value) {
|
||||
labels += label.replace("labelName", value.name).replace("labelValue", value.value)
|
||||
});
|
||||
$(".labels-menu").append(labels);
|
||||
requesting = false;
|
||||
},
|
||||
error: function() {
|
||||
requesting = false;
|
||||
},
|
||||
flash_message: false
|
||||
};
|
||||
requesting = true;
|
||||
requestApi(data)
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
loadLabels()
|
||||
}).on('click', '.labels-menu li', function () {
|
||||
var val = $(this).text();
|
||||
$("#user_assets_table_filter input").val(val);
|
||||
assetTable.search(val).draw();
|
||||
})
|
||||
</script>
|
|
@ -280,7 +280,7 @@ function updateUserGroups(groups) {
|
|||
// clear jumpserver.groups_selected
|
||||
jumpserver.nodes_selected = {};
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -305,7 +305,7 @@ $(document).ready(function() {
|
|||
'is_active': checked
|
||||
};
|
||||
var success = '{% trans "Update successfully!" %}';
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success_message: success
|
||||
|
@ -332,7 +332,7 @@ $(document).ready(function() {
|
|||
'otp_secret_key': otp_secret_key
|
||||
};
|
||||
var success = '{% trans "Update successfully!" %}';
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success_message: success
|
||||
|
@ -372,7 +372,7 @@ $(document).ready(function() {
|
|||
var msg = "{% trans "An e-mail has been sent to the user`s mailbox." %}";
|
||||
swal("{% trans 'Reset password' %}", msg, "success");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -398,7 +398,7 @@ $(document).ready(function() {
|
|||
var msg = "{% trans 'The reset-ssh-public-key E-mail has been sent successfully. Please inform the user to update his new ssh public key.' %}";
|
||||
swal("{% trans 'Reset SSH public key' %}", msg, "success");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: body,
|
||||
success: success
|
||||
|
@ -441,7 +441,7 @@ $(document).ready(function() {
|
|||
}
|
||||
);
|
||||
};
|
||||
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
||||
requestApi({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
||||
}).on('click', '.btn-delete-user', function () {
|
||||
var $this = $(this);
|
||||
var name = "{{ user_object.name }}";
|
||||
|
@ -466,7 +466,7 @@ $(document).ready(function() {
|
|||
}
|
||||
);
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
@ -485,7 +485,7 @@ $(document).ready(function() {
|
|||
doReset();
|
||||
});
|
||||
}).on('click', '#btn-reset-mfa', function () {
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: "{% url 'api-users:user-reset-otp' pk=user_object.id %}",
|
||||
method: "GET",
|
||||
success_message: "{% trans 'Reset user MFA success' %}"
|
||||
|
|
|
@ -23,33 +23,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-lg-3" style="padding-left: 0px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight">
|
||||
<div class="mail-box-header">
|
||||
<table class="table table-striped table-bordered table-hover" id="user_assets_table" >
|
||||
<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 'System users' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_granted_assets.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -58,81 +32,10 @@
|
|||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
var zTree;
|
||||
var inited = false;
|
||||
var url;
|
||||
var asset_table;
|
||||
var assetTableUrl = "{% url 'api-perms:user-assets' pk=object.id %}?cache_policy=1";
|
||||
var selectUrl = '{% url "api-perms:user-node-assets" pk=object.id node_id=DEFAULT_PK %}?cache_policy=1';
|
||||
var treeUrl = "{% url 'api-perms:user-nodes-as-tree' pk=object.id %}?&cache_policy=1";
|
||||
|
||||
function initTable() {
|
||||
if (inited){
|
||||
return asset_table
|
||||
} else {
|
||||
inited = true;
|
||||
}
|
||||
url = "{% url 'api-perms:user-assets' pk=object.id %}?cache_policy=1";
|
||||
var options = {
|
||||
ele: $('#user_assets_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
cellData = htmlEscape(cellData);
|
||||
{% 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) {
|
||||
var users = [];
|
||||
$.each(cellData, function (id, data) {
|
||||
var name = htmlEscape(data.name);
|
||||
users.push(name);
|
||||
});
|
||||
$(td).html(users.join(', '))
|
||||
}}
|
||||
],
|
||||
ajax_url: url,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "system_users_granted", orderable: false}
|
||||
]
|
||||
};
|
||||
asset_table = jumpserver.initServerSideDataTable(options)
|
||||
}
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
url = '{% url "api-perms:user-node-assets" pk=object.id node_id=DEFAULT_PK %}?cache_policy=1';
|
||||
var node_id = treeNode.meta.node.id;
|
||||
url = url.replace("{{ DEFAULT_PK }}", node_id);
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected
|
||||
}
|
||||
};
|
||||
|
||||
$.get(treeUrl, function(data, status) {
|
||||
$.fn.zTree.init($("#assetTree"), setting, data);
|
||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||
rootNodeAddDom(zTree, function () {
|
||||
treeUrl = treeUrl.replace('cache_policy=1', 'cache_policy=2');
|
||||
initTree();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
initTree();
|
||||
initTable();
|
||||
|
|
|
@ -142,7 +142,7 @@ function updateGroupMember(users) {
|
|||
// clear jumpserver.selected_groups
|
||||
jumpserver.users_selected = {};
|
||||
};
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
body: JSON.stringify(body),
|
||||
success: success
|
||||
|
|
|
@ -23,142 +23,21 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="col-lg-3" style="padding-left: 0px">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-content mailbox-content" style="padding-top: 0">
|
||||
<div class="file-manager ">
|
||||
<div id="assetTree" class="ztree">
|
||||
</div>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-9 animated fadeInRight">
|
||||
<div class="mail-box-header">
|
||||
<table class="table table-striped table-bordered table-hover" id="user_assets_table" >
|
||||
<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 'Active' %}</th>
|
||||
<th class="text-center">{% trans 'Reachable' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'users/_granted_assets.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
var zTree;
|
||||
var inited = false;
|
||||
var url;
|
||||
var asset_table;
|
||||
var treeUrl = "{% url 'api-perms:user-group-nodes-as-tree' pk=object.id %}?cache_policy=1";
|
||||
var assetTableUrl = "{% url 'api-perms:user-group-assets' pk=object.id %}?cache_policy=1";
|
||||
var selectUrl = '{% url "api-perms:user-group-node-assets" pk=object.id node_id=DEFAULT_PK %}?cache_policy=1';
|
||||
var showAssetHref = true; // Need input default true
|
||||
|
||||
function initTable() {
|
||||
if (inited){
|
||||
return asset_table
|
||||
} else {
|
||||
inited = true;
|
||||
}
|
||||
url = "{% url 'api-perms:user-group-assets' pk=object.id %}";
|
||||
var options = {
|
||||
ele: $('#user_assets_table'),
|
||||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
cellData = htmlEscape(cellData);
|
||||
{% 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) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
} else {
|
||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
||||
}
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData) {
|
||||
var users = [];
|
||||
$.each(cellData, function (id, data) {
|
||||
var name = htmlEscape(data.name);
|
||||
users.push(name);
|
||||
});
|
||||
$(td).html(users.join(', '))
|
||||
}}
|
||||
],
|
||||
ajax_url: url,
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" },
|
||||
{data: "is_active", orderable: false },
|
||||
{data: "system_users_granted", orderable: false}
|
||||
]
|
||||
};
|
||||
asset_table = jumpserver.initDataTable(options);
|
||||
return asset_table
|
||||
}
|
||||
|
||||
|
||||
function onSelected(event, treeNode) {
|
||||
url = '{% url "api-perms:user-group-node-assets" pk=object.id node_id=DEFAULT_PK %}';
|
||||
var node_id = treeNode.meta.node.id;
|
||||
url = url.replace("{{ DEFAULT_PK }}", node_id);
|
||||
asset_table.ajax.url(url);
|
||||
asset_table.ajax.reload();
|
||||
}
|
||||
|
||||
|
||||
function selectQueryNode() {
|
||||
var query_node_id = $.getUrlParam("node");
|
||||
var cookie_node_id = getCookie('node_selected');
|
||||
var node;
|
||||
var node_id;
|
||||
|
||||
if (query_node_id !== null) {
|
||||
node_id = query_node_id
|
||||
} else if (cookie_node_id !== null) {
|
||||
node_id = cookie_node_id;
|
||||
}
|
||||
|
||||
node = zTree.getNodesByParam("id", node_id, null);
|
||||
if (node){
|
||||
zTree.selectNode(node[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function initTree() {
|
||||
var setting = {
|
||||
view: {
|
||||
dblClickExpand: false,
|
||||
showLine: true
|
||||
},
|
||||
data: {
|
||||
simpleData: {
|
||||
enable: true
|
||||
}
|
||||
},
|
||||
callback: {
|
||||
onSelected: onSelected
|
||||
}
|
||||
};
|
||||
|
||||
$.get("{% url 'api-perms:user-group-nodes-assets-as-tree' pk=object.id %}?show_assets=0", function(data, status) {
|
||||
$.fn.zTree.init($("#assetTree"), setting, data);
|
||||
zTree = $.fn.zTree.getZTreeObj("assetTree");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
initTree();
|
||||
|
|
|
@ -129,7 +129,7 @@ $(document).ready(function() {
|
|||
swal("{% trans 'UserGroups Delete' %}", msg, "error");
|
||||
};
|
||||
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
|
||||
APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
|
||||
requestApi({url: url_delete, method: 'DELETE', success: success, error: fail});
|
||||
jumpserver.checked = false;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@ $(document).ready(function(){
|
|||
setTimeout( function () {
|
||||
window.location.reload();}, 300);
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
|
@ -239,7 +239,7 @@ $(document).ready(function(){
|
|||
setTimeout( function () {
|
||||
window.location.reload();}, 300);
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: the_url,
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
|
@ -259,7 +259,7 @@ $(document).ready(function(){
|
|||
},function () {
|
||||
function success(data) {
|
||||
url = setUrlParam(the_url, 'spm', data.spm);
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url:url,
|
||||
method:'DELETE',
|
||||
success:refreshTag,
|
||||
|
@ -272,7 +272,7 @@ $(document).ready(function(){
|
|||
var msg = "{% trans 'User Deleting failed.' %}";
|
||||
swal("{% trans 'User Delete' %}", msg, "error");
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: "{% url 'api-common:resources-cache' %}",
|
||||
method:'POST',
|
||||
body:JSON.stringify(data),
|
||||
|
@ -290,7 +290,7 @@ $(document).ready(function(){
|
|||
var url = "{% url 'users:user-bulk-update' %}";
|
||||
location.href= setUrlParam(url, 'spm', data.spm);
|
||||
}
|
||||
APIUpdateAttr({
|
||||
requestApi({
|
||||
url: "{% url 'api-common:resources-cache' %}",
|
||||
method:'POST',
|
||||
body:JSON.stringify(data),
|
||||
|
|
Loading…
Reference in New Issue