diff --git a/apps/assets/api/admin_user.py b/apps/assets/api/admin_user.py index 7048ce461..8d30ee9d9 100644 --- a/apps/assets/api/admin_user.py +++ b/apps/assets/api/admin_user.py @@ -17,6 +17,7 @@ from django.db import transaction from rest_framework import generics from rest_framework.response import Response from rest_framework_bulk import BulkModelViewSet +from rest_framework.pagination import LimitOffsetPagination from common.mixins import IDInFilterMixin from common.utils import get_logger @@ -37,9 +38,17 @@ class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet): """ Admin user api set, for add,delete,update,list,retrieve resource """ + + filter_fields = ("name", "username") + search_fields = filter_fields queryset = AdminUser.objects.all() serializer_class = serializers.AdminUserSerializer permission_classes = (IsOrgAdmin,) + pagination_class = LimitOffsetPagination + + def get_queryset(self): + queryset = super().get_queryset().all() + return queryset class AdminUserAuthApi(generics.UpdateAPIView): diff --git a/apps/assets/api/cmd_filter.py b/apps/assets/api/cmd_filter.py index 14afc0ae3..cecdf2432 100644 --- a/apps/assets/api/cmd_filter.py +++ b/apps/assets/api/cmd_filter.py @@ -2,6 +2,7 @@ # from rest_framework_bulk import BulkModelViewSet +from rest_framework.pagination import LimitOffsetPagination from django.shortcuts import get_object_or_404 from ..hands import IsOrgAdmin @@ -13,14 +14,20 @@ __all__ = ['CommandFilterViewSet', 'CommandFilterRuleViewSet'] class CommandFilterViewSet(BulkModelViewSet): + filter_fields = ("name",) + search_fields = filter_fields permission_classes = (IsOrgAdmin,) queryset = CommandFilter.objects.all() serializer_class = serializers.CommandFilterSerializer + pagination_class = LimitOffsetPagination class CommandFilterRuleViewSet(BulkModelViewSet): + filter_fields = ("content",) + search_fields = filter_fields permission_classes = (IsOrgAdmin,) serializer_class = serializers.CommandFilterRuleSerializer + pagination_class = LimitOffsetPagination def get_queryset(self): fpk = self.kwargs.get('filter_pk') diff --git a/apps/assets/api/domain.py b/apps/assets/api/domain.py index 37bebfb84..2e24829dc 100644 --- a/apps/assets/api/domain.py +++ b/apps/assets/api/domain.py @@ -2,6 +2,7 @@ from rest_framework_bulk import BulkModelViewSet from rest_framework.views import APIView, Response +from rest_framework.pagination import LimitOffsetPagination from django.views.generic.detail import SingleObjectMixin @@ -20,6 +21,11 @@ class DomainViewSet(BulkModelViewSet): queryset = Domain.objects.all() permission_classes = (IsOrgAdmin,) serializer_class = serializers.DomainSerializer + pagination_class = LimitOffsetPagination + + def get_queryset(self): + queryset = super().get_queryset().all() + return queryset def get_serializer_class(self): if self.request.query_params.get('gateway'): @@ -33,11 +39,12 @@ class DomainViewSet(BulkModelViewSet): class GatewayViewSet(BulkModelViewSet): - filter_fields = ("domain",) + filter_fields = ("domain__name", "name", "username", "ip") search_fields = filter_fields queryset = Gateway.objects.all() permission_classes = (IsOrgAdmin,) serializer_class = serializers.GatewaySerializer + pagination_class = LimitOffsetPagination class GatewayTestConnectionApi(SingleObjectMixin, APIView): diff --git a/apps/assets/api/label.py b/apps/assets/api/label.py index e5391c76a..eb8594e4a 100644 --- a/apps/assets/api/label.py +++ b/apps/assets/api/label.py @@ -14,6 +14,7 @@ # 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 @@ -27,8 +28,11 @@ __all__ = ['LabelViewSet'] class LabelViewSet(BulkModelViewSet): + filter_fields = ("name", "value") + search_fields = filter_fields permission_classes = (IsOrgAdmin,) serializer_class = serializers.LabelSerializer + pagination_class = LimitOffsetPagination def list(self, request, *args, **kwargs): if request.query_params.get("distinct"): diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py index 16d475c35..3c1d0b3bd 100644 --- a/apps/assets/api/system_user.py +++ b/apps/assets/api/system_user.py @@ -42,9 +42,16 @@ class SystemUserViewSet(BulkModelViewSet): """ System user api set, for add,delete,update,list,retrieve resource """ + filter_fields = ("name", "username") + search_fields = filter_fields queryset = SystemUser.objects.all() serializer_class = serializers.SystemUserSerializer permission_classes = (IsOrgAdminOrAppUser,) + pagination_class = LimitOffsetPagination + + def get_queryset(self): + queryset = super().get_queryset().all() + return queryset class SystemUserAuthInfoApi(generics.RetrieveUpdateDestroyAPIView): diff --git a/apps/assets/templates/assets/admin_user_list.html b/apps/assets/templates/assets/admin_user_list.html index 16fcd1950..25ee56fba 100644 --- a/apps/assets/templates/assets/admin_user_list.html +++ b/apps/assets/templates/assets/admin_user_list.html @@ -93,7 +93,7 @@ $(document).ready(function(){ columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" }, {data: "reachable_amount"}, {data: "unreachable_amount"}, {data: "id"}, {data: "comment" }, {data: "id" }] }; - jumpserver.initDataTable(options); + jumpserver.initServerSideDataTable(options) }) .on('click', '.btn_admin_user_delete', function () { diff --git a/apps/assets/templates/assets/cmd_filter_list.html b/apps/assets/templates/assets/cmd_filter_list.html index 78060177b..3a4feeae0 100644 --- a/apps/assets/templates/assets/cmd_filter_list.html +++ b/apps/assets/templates/assets/cmd_filter_list.html @@ -66,7 +66,7 @@ function initTable() { ], op_html: $('#actions').html() }; - jumpserver.initDataTable(options); + jumpserver.initServerSideDataTable(options); } $(document).ready(function(){ initTable(); diff --git a/apps/assets/templates/assets/cmd_filter_rule_list.html b/apps/assets/templates/assets/cmd_filter_rule_list.html index 119b44fd4..78c3a36d5 100644 --- a/apps/assets/templates/assets/cmd_filter_rule_list.html +++ b/apps/assets/templates/assets/cmd_filter_rule_list.html @@ -95,7 +95,7 @@ function initTable() { ], op_html: $('#actions').html() }; - jumpserver.initDataTable(options); + jumpserver.initServerSideDataTable(options); } $(document).ready(function(){ initTable(); diff --git a/apps/assets/templates/assets/domain_gateway_list.html b/apps/assets/templates/assets/domain_gateway_list.html index 43e8f43df..e7a3467e3 100644 --- a/apps/assets/templates/assets/domain_gateway_list.html +++ b/apps/assets/templates/assets/domain_gateway_list.html @@ -98,7 +98,7 @@ function initTable() { ], op_html: $('#actions').html() }; - jumpserver.initDataTable(options); + jumpserver.initServerSideDataTable(options); } $(document).ready(function(){ initTable(); diff --git a/apps/assets/templates/assets/domain_list.html b/apps/assets/templates/assets/domain_list.html index 6913671f4..a0c6e869e 100644 --- a/apps/assets/templates/assets/domain_list.html +++ b/apps/assets/templates/assets/domain_list.html @@ -62,7 +62,7 @@ function initTable() { ], op_html: $('#actions').html() }; - jumpserver.initDataTable(options); + jumpserver.initServerSideDataTable(options); } $(document).ready(function(){ initTable(); diff --git a/apps/assets/templates/assets/label_list.html b/apps/assets/templates/assets/label_list.html index 1c1b380d5..d2fa9958a 100644 --- a/apps/assets/templates/assets/label_list.html +++ b/apps/assets/templates/assets/label_list.html @@ -47,7 +47,7 @@ function initTable() { ], op_html: $('#actions').html() }; - jumpserver.initDataTable(options); + jumpserver.initServerSideDataTable(options); } $(document).ready(function(){ initTable(); diff --git a/apps/assets/templates/assets/system_user_list.html b/apps/assets/templates/assets/system_user_list.html index 2d1358e46..f7c2a613b 100644 --- a/apps/assets/templates/assets/system_user_list.html +++ b/apps/assets/templates/assets/system_user_list.html @@ -100,7 +100,7 @@ function initTable() { ], op_html: $('#actions').html() }; - jumpserver.initDataTable(options); + jumpserver.initServerSideDataTable(options); } $(document).ready(function(){ diff --git a/apps/assets/templates/assets/user_asset_list.html b/apps/assets/templates/assets/user_asset_list.html index 2f03a361d..1b1a76e1d 100644 --- a/apps/assets/templates/assets/user_asset_list.html +++ b/apps/assets/templates/assets/user_asset_list.html @@ -102,7 +102,7 @@ function initTable() { {data: "system_users_granted", orderable: false} ] }; - asset_table = jumpserver.initDataTable(options); + asset_table = jumpserver.initServerSideDataTable(options); return asset_table } diff --git a/apps/common/mixins.py b/apps/common/mixins.py index ceeaed6c1..0a7d15fef 100644 --- a/apps/common/mixins.py +++ b/apps/common/mixins.py @@ -117,6 +117,3 @@ class DatetimeSearchMixin: def get(self, request, *args, **kwargs): self.get_date_range() return super().get(request, *args, **kwargs) - - - diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index b91198c4a..1315c19c3 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 402d71d67..9e3459248 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -1363,7 +1363,7 @@ msgstr "创建命令过滤器" #: assets/templates/assets/cmd_filter_rule_list.html:33 #: assets/views/cmd_filter.py:98 msgid "Command filter rule list" -msgstr "命令过滤器列表" +msgstr "命令过滤器规则列表" #: assets/templates/assets/cmd_filter_rule_list.html:50 msgid "Create rule" @@ -2477,8 +2477,8 @@ msgstr "用户或用户组" #: perms/templates/perms/asset_permission_asset.html:27 #: perms/templates/perms/asset_permission_detail.html:27 #: perms/templates/perms/asset_permission_user.html:27 -msgid "Assets and asset groups" -msgstr "资产或资产组" +msgid "Assets and node" +msgstr "资产或节点" #: perms/templates/perms/asset_permission_asset.html:80 msgid "Add asset to this permission" diff --git a/apps/perms/api.py b/apps/perms/api.py index 910ffb7f9..a1472d46a 100644 --- a/apps/perms/api.py +++ b/apps/perms/api.py @@ -5,6 +5,7 @@ from django.shortcuts import get_object_or_404 from rest_framework.views import APIView, Response from rest_framework.generics import ListAPIView, get_object_or_404, RetrieveUpdateAPIView from rest_framework import viewsets +from rest_framework.pagination import LimitOffsetPagination from common.utils import set_or_append_attr_bulk from common.permissions import IsValidUser, IsOrgAdmin, IsOrgAdminOrAppUser @@ -15,6 +16,7 @@ from .hands import AssetGrantedSerializer, User, UserGroup, Asset, Node, \ NodeGrantedSerializer, SystemUser, NodeSerializer from orgs.utils import set_to_root_org from . import serializers +from .mixins import AssetsFilterMixin class AssetPermissionViewSet(viewsets.ModelViewSet): @@ -23,6 +25,7 @@ class AssetPermissionViewSet(viewsets.ModelViewSet): """ queryset = AssetPermission.objects.all() serializer_class = serializers.AssetPermissionCreateUpdateSerializer + pagination_class = LimitOffsetPagination permission_classes = (IsOrgAdmin,) def get_serializer_class(self): @@ -31,10 +34,15 @@ class AssetPermissionViewSet(viewsets.ModelViewSet): return self.serializer_class def get_queryset(self): - queryset = super().get_queryset() + queryset = super().get_queryset().all() + search = self.request.query_params.get('search') asset_id = self.request.query_params.get('asset') node_id = self.request.query_params.get('node') inherit_nodes = set() + + if search: + queryset = queryset.filter(name__icontains=search) + if not asset_id and not node_id: return queryset @@ -53,15 +61,17 @@ class AssetPermissionViewSet(viewsets.ModelViewSet): _permissions = queryset.filter(nodes=n) set_or_append_attr_bulk(_permissions, "inherit", n.value) permissions.update(_permissions) - return permissions + + return list(permissions) -class UserGrantedAssetsApi(ListAPIView): +class UserGrantedAssetsApi(AssetsFilterMixin, ListAPIView): """ 用户授权的所有资产 """ permission_classes = (IsOrgAdminOrAppUser,) serializer_class = AssetGrantedSerializer + pagination_class = LimitOffsetPagination def change_org_if_need(self): if self.request.user.is_superuser or \ @@ -84,6 +94,7 @@ class UserGrantedAssetsApi(ListAPIView): system_users_granted = [s for s in v if s.protocol == k.protocol] k.system_users_granted = system_users_granted queryset.append(k) + return queryset def get_permissions(self): @@ -122,7 +133,7 @@ class UserGrantedNodesApi(ListAPIView): return super().get_permissions() -class UserGrantedNodesWithAssetsApi(ListAPIView): +class UserGrantedNodesWithAssetsApi(AssetsFilterMixin, ListAPIView): """ 用户授权的节点并带着节点下资产的api """ @@ -155,19 +166,25 @@ class UserGrantedNodesWithAssetsApi(ListAPIView): queryset.append(node) return queryset + def sort_assets(self, queryset): + for node in queryset: + node.assets_granted = super().sort_assets(node.assets_granted) + return queryset + def get_permissions(self): if self.kwargs.get('pk') is None: self.permission_classes = (IsValidUser,) return super().get_permissions() -class UserGrantedNodeAssetsApi(ListAPIView): +class UserGrantedNodeAssetsApi(AssetsFilterMixin, ListAPIView): """ 查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产 """ permission_classes = (IsOrgAdminOrAppUser,) serializer_class = AssetGrantedSerializer - + pagination_class = LimitOffsetPagination + def change_org_if_need(self): if self.request.user.is_superuser or \ self.request.user.is_app or \ @@ -189,6 +206,8 @@ class UserGrantedNodeAssetsApi(ListAPIView): assets = nodes.get(node, []) for asset, system_users in assets.items(): asset.system_users_granted = system_users + + assets = list(assets.keys()) return assets def get_permissions(self): diff --git a/apps/perms/mixins.py b/apps/perms/mixins.py new file mode 100644 index 000000000..e41c0529b --- /dev/null +++ b/apps/perms/mixins.py @@ -0,0 +1,36 @@ +# ~*~ coding: utf-8 ~*~ +# + + +class AssetsFilterMixin(object): + """ + 对资产进行过滤(查询,排序) + """ + + def filter_queryset(self, queryset): + queryset = self.search_assets(queryset) + queryset = self.sort_assets(queryset) + return queryset + + def search_assets(self, queryset): + from perms.utils import is_obj_attr_has + value = self.request.query_params.get('search') + if not value: + return queryset + queryset = [asset for asset in queryset if is_obj_attr_has(asset, value)] + return queryset + + def sort_assets(self, queryset): + from perms.utils import sort_assets + order_by = self.request.query_params.get('order') + if not order_by: + order_by = 'hostname' + + if order_by.startswith('-'): + order_by = order_by.lstrip('-') + reverse = True + else: + reverse = False + + queryset = sort_assets(queryset, order_by=order_by, reverse=reverse) + return queryset diff --git a/apps/perms/templates/perms/asset_permission_asset.html b/apps/perms/templates/perms/asset_permission_asset.html index 364d7e60f..e774692f3 100644 --- a/apps/perms/templates/perms/asset_permission_asset.html +++ b/apps/perms/templates/perms/asset_permission_asset.html @@ -24,7 +24,7 @@