mirror of https://github.com/jumpserver/jumpserver
[Update] 优化授权规则资产列表页面 (#2937)
* [Update] 优化授权规则资产列表页面 * [Update] 优化授权规则资产列表页面2 * [Update] 优化授权规则资产列表页面3 * [Update] 优化授权规则资产列表页面4 * [Update] 优化授权规则资产列表页面5 * [Update] 优化授权规则资产列表页面6pull/2942/head
parent
7bda48bd9f
commit
e5bdceed58
|
@ -4,7 +4,8 @@
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from rest_framework.views import Response
|
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 import viewsets
|
||||||
from rest_framework.pagination import LimitOffsetPagination
|
from rest_framework.pagination import LimitOffsetPagination
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ from .. import serializers
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
|
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
|
||||||
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
|
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
|
||||||
'AssetPermissionAddAssetApi',
|
'AssetPermissionAddAssetApi', 'AssetPermissionAssetsApi',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -232,3 +233,22 @@ class AssetPermissionAddAssetApi(RetrieveUpdateAPIView):
|
||||||
return Response({"msg": "ok"})
|
return Response({"msg": "ok"})
|
||||||
else:
|
else:
|
||||||
return Response({"error": serializer.errors})
|
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
|
||||||
|
|
|
@ -2,6 +2,7 @@ import uuid
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from common.utils import date_expired_default, set_or_append_attr_bulk
|
from common.utils import date_expired_default, set_or_append_attr_bulk
|
||||||
|
@ -93,11 +94,16 @@ class AssetPermission(BasePermission):
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_all_assets(self):
|
def get_all_assets(self):
|
||||||
assets = set(self.assets.all())
|
args = [Q(granted_by_permissions=self)]
|
||||||
for node in self.nodes.all():
|
pattern = set()
|
||||||
_assets = node.get_all_assets()
|
nodes_keys = self.nodes.all().values_list('key', flat=True)
|
||||||
set_or_append_attr_bulk(_assets, 'inherit', node.value)
|
for key in nodes_keys:
|
||||||
assets.update(set(_assets))
|
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
|
return assets
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,12 @@ from rest_framework import serializers
|
||||||
from common.fields import StringManyToManyField
|
from common.fields import StringManyToManyField
|
||||||
from orgs.mixins import BulkOrgResourceModelSerializer
|
from orgs.mixins import BulkOrgResourceModelSerializer
|
||||||
from perms.models import AssetPermission, Action
|
from perms.models import AssetPermission, Action
|
||||||
|
from assets.models import Asset
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
|
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
|
||||||
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
|
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
|
||||||
'ActionsField',
|
'ActionsField', 'AssetPermissionAssetsSerializer',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,3 +71,11 @@ class AssetPermissionUpdateAssetSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AssetPermission
|
model = AssetPermission
|
||||||
fields = ['id', 'assets']
|
fields = ['id', 'assets']
|
||||||
|
|
||||||
|
|
||||||
|
class AssetPermissionAssetsSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Asset
|
||||||
|
only_fields = ['id', 'hostname', 'ip']
|
||||||
|
fields = tuple(only_fields)
|
||||||
|
|
|
@ -48,29 +48,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<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>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'Hostname' %}</th>
|
<th class="text-center">
|
||||||
<th>{% trans 'IP' %}</th>
|
<input type="checkbox" id="check_all" class="ipt_check_all" >
|
||||||
<th></th>
|
</th>
|
||||||
</tr>
|
<th class="text-center">{% trans 'Hostname' %}</th>
|
||||||
|
<th class="text-center">{% trans 'IP' %}</th>
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="row">
|
|
||||||
{% include '_pagination.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,9 +76,6 @@
|
||||||
<tr class="no-borders-tr">
|
<tr class="no-borders-tr">
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<select data-placeholder="{% trans 'Select assets' %}" class="select2" id="asset_select2" 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 }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -146,6 +133,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% include 'assets/_asset_list_modal.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
|
@ -162,7 +150,7 @@ function addAssets(assets) {
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
success: success
|
success: success
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeAssets(assets) {
|
function removeAssets(assets) {
|
||||||
var the_url = "{% url 'api-perms:asset-permission-remove-asset' pk=asset_permission.id %}";
|
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 () {
|
$(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 () {
|
.on('click', '.btn-add-assets', function () {
|
||||||
var assets_selected = $("#asset_select2 option:selected").map(function () {
|
var assets_selected = $("#asset_select2 option:selected").map(function () {
|
||||||
|
@ -237,7 +273,7 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
updateNodes(nodes, success);
|
updateNodes(nodes, success);
|
||||||
})
|
})
|
||||||
.on('click', '.btn-remove-node', function () {
|
.on('click', '.btn-remove-node', function () {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var $tr = $this.closest('tr');
|
var $tr = $this.closest('tr');
|
||||||
|
|
|
@ -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/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>/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/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'),
|
path('asset-permissions/user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'),
|
||||||
|
|
|
@ -163,12 +163,12 @@ class AssetPermissionAssetView(PermissionsMixin,
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
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 = {
|
context = {
|
||||||
'app': _('Perms'),
|
'app': _('Perms'),
|
||||||
'action': _('Asset permission asset list'),
|
'action': _('Asset permission asset list'),
|
||||||
'assets_remain': Asset.objects.exclude(id__in=[a.id for a in assets_granted]),
|
'nodes_remain': nodes_remain,
|
||||||
'nodes_remain': Node.objects.exclude(granted_by_permissions=self.object),
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
Loading…
Reference in New Issue