[Update] 优化授权规则资产列表页面 (#2937)

* [Update] 优化授权规则资产列表页面

* [Update] 优化授权规则资产列表页面2

* [Update] 优化授权规则资产列表页面3

* [Update] 优化授权规则资产列表页面4

* [Update] 优化授权规则资产列表页面5

* [Update] 优化授权规则资产列表页面6
pull/2942/head
BaiJiangJie 2019-07-12 18:31:14 +08:00 committed by 老广
parent 7bda48bd9f
commit e5bdceed58
6 changed files with 109 additions and 35 deletions

View File

@ -4,7 +4,8 @@
from django.utils import timezone
from django.db.models import Q
from rest_framework.views import Response
from rest_framework.generics import RetrieveUpdateAPIView
from django.shortcuts import get_object_or_404
from rest_framework.generics import RetrieveUpdateAPIView, ListAPIView
from rest_framework import viewsets
from rest_framework.pagination import LimitOffsetPagination
@ -20,7 +21,7 @@ from .. import serializers
__all__ = [
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
'AssetPermissionAddAssetApi',
'AssetPermissionAddAssetApi', 'AssetPermissionAssetsApi',
]
@ -232,3 +233,22 @@ class AssetPermissionAddAssetApi(RetrieveUpdateAPIView):
return Response({"msg": "ok"})
else:
return Response({"error": serializer.errors})
class AssetPermissionAssetsApi(ListAPIView):
permission_classes = (IsOrgAdmin,)
pagination_class = LimitOffsetPagination
serializer_class = serializers.AssetPermissionAssetsSerializer
filter_fields = ("hostname", "ip")
search_fields = filter_fields
def get_object(self):
pk = self.kwargs.get('pk')
return get_object_or_404(AssetPermission, pk=pk)
def get_queryset(self):
perm = self.get_object()
assets = perm.get_all_assets().only(
*self.serializer_class.Meta.only_fields
)
return assets

View File

@ -2,6 +2,7 @@ import uuid
from functools import reduce
from django.db import models
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from common.utils import date_expired_default, set_or_append_attr_bulk
@ -93,11 +94,16 @@ class AssetPermission(BasePermission):
)
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))
args = [Q(granted_by_permissions=self)]
pattern = set()
nodes_keys = self.nodes.all().values_list('key', flat=True)
for key in nodes_keys:
pattern.add(r'^{0}$|^{0}:'.format(key))
pattern = '|'.join(list(pattern))
if pattern:
args.append(Q(nodes__key__regex=pattern))
args = reduce(lambda x, y: x | y, args)
assets = Asset.objects.filter(args)
return assets

View File

@ -6,11 +6,12 @@ from rest_framework import serializers
from common.fields import StringManyToManyField
from orgs.mixins import BulkOrgResourceModelSerializer
from perms.models import AssetPermission, Action
from assets.models import Asset
__all__ = [
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
'ActionsField',
'ActionsField', 'AssetPermissionAssetsSerializer',
]
@ -70,3 +71,11 @@ class AssetPermissionUpdateAssetSerializer(serializers.ModelSerializer):
class Meta:
model = AssetPermission
fields = ['id', 'assets']
class AssetPermissionAssetsSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
only_fields = ['id', 'hostname', 'ip']
fields = tuple(only_fields)

View File

@ -48,29 +48,19 @@
</div>
</div>
<div class="ibox-content">
<table class="table table-hover">
<table class="table table-striped table-bordered table-hover" id="asset_list_table" style="width: 100%">
<thead>
<tr>
<th>{% trans 'Hostname' %}</th>
<th>{% trans 'IP' %}</th>
<th></th>
</tr>
<tr>
<th class="text-center">
<input type="checkbox" id="check_all" class="ipt_check_all" >
</th>
<th class="text-center">{% trans 'Hostname' %}</th>
<th class="text-center">{% trans 'IP' %}</th>
</tr>
</thead>
<tbody>
{% for asset in object_list %}
<tr>
<td>{{ asset.hostname }}</td>
<td>{{ asset.ip }}</td>
<td>
<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 %}
</tbody>
</table>
<div class="row">
{% include '_pagination.html' %}
</div>
</div>
</div>
</div>
@ -86,9 +76,6 @@
<tr class="no-borders-tr">
<td colspan="2">
<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 }}</option>
{% endfor %}
</select>
</td>
</tr>
@ -146,6 +133,7 @@
</div>
</div>
{% include 'assets/_asset_list_modal.html' %}
{% endblock %}
{% block custom_foot_js %}
<script>
@ -162,7 +150,7 @@ function addAssets(assets) {
body: JSON.stringify(body),
success: success
});
}
}
function removeAssets(assets) {
var the_url = "{% url 'api-perms:asset-permission-remove-asset' pk=asset_permission.id %}";
@ -191,9 +179,57 @@ function updateNodes(nodes, success) {
});
}
var table;
function initAssetTable() {
var options = {
ele: $('#asset_list_table'),
toggle: true,
columnDefs: [
{
targets: 0, createdCell: function (td, cellData, rowData) {
var html = '<input type="checkbox" class="text-center ipt_check" id="id_' + cellData + '">';
$(td).html(html);
}
},
],
ajax_url: "{% url 'api-perms:asset-permission-assets' pk=object.id %}",
columns: [
{data: "id"}, {data: "hostname"}, {data: "ip"}
],
op_html: $('#actions').html()
};
table = jumpserver.initServerSideDataTable(options);
return table
}
$(document).ready(function () {
$('.select2').select2();
$('.select2').select2();
table = initAssetTable();
$("#asset_select2").parent().find(".select2-selection").on('click', function (e) {
if ($(e.target).attr('class') !== 'select2-selection__choice__remove'){
e.preventDefault();
e.stopPropagation();
$("#asset_list_modal").modal();
initSelectedAssets2Table('#asset_select2');
}
})
})
.on('click', '#btn_asset_modal_confirm', function () {
var assets = asset_table2.selected;
var options = [];
$('#asset_select2 option').each(function (i, v) {
options.push(v.value)
});
asset_table2.selected_rows.forEach(function (i) {
var name = i.hostname + '(' + i.ip + ')';
var option = new Option(name, i.id, false, true);
if (options.indexOf(i.id) === -1) {
$('#asset_select2').append(option).trigger('change');
}
});
$('#asset_select2').val(assets).trigger('change');
$("#asset_list_modal").modal('hide');
})
.on('click', '.btn-add-assets', function () {
var assets_selected = $("#asset_select2 option:selected").map(function () {
@ -237,7 +273,7 @@ $(document).ready(function () {
});
};
updateNodes(nodes, success);
})
})
.on('click', '.btn-remove-node', function () {
var $this = $(this);
var $tr = $this.closest('tr');

View File

@ -50,6 +50,9 @@ asset_permission_urlpatterns = [
path('asset-permissions/<uuid:pk>/asset/remove/', api.AssetPermissionRemoveAssetApi.as_view(), name='asset-permission-remove-asset'),
path('asset-permissions/<uuid:pk>/asset/add/', api.AssetPermissionAddAssetApi.as_view(), name='asset-permission-add-asset'),
# 授权规则中授权的资产
path('asset-permissions/<uuid:pk>/assets/', api.AssetPermissionAssetsApi.as_view(), name='asset-permission-assets'),
# 验证用户是否有某个资产和系统用户的权限
path('asset-permissions/user/validate/', api.ValidateUserAssetPermissionApi.as_view(), name='validate-user-asset-permission'),
path('asset-permissions/user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'),

View File

@ -163,12 +163,12 @@ class AssetPermissionAssetView(PermissionsMixin,
return queryset
def get_context_data(self, **kwargs):
assets_granted = self.get_queryset()
granted_nodes = self.object.nodes.all()
nodes_remain = [n for n in Node.get_queryset() if n not in granted_nodes]
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),
'nodes_remain': nodes_remain,
}
kwargs.update(context)
return super().get_context_data(**kwargs)