mirror of https://github.com/jumpserver/jumpserver
Merge branch 'paging' into dev
commit
cc18ad9a7f
|
@ -19,8 +19,9 @@ from rest_framework_bulk import BulkModelViewSet
|
|||
from rest_framework_bulk import ListBulkCreateUpdateDestroyAPIView
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.db.models import Q
|
||||
from rest_framework.pagination import LimitOffsetPagination
|
||||
|
||||
from common.mixins import IDInFilterMixin
|
||||
from common.mixins import CustomFilterMixin
|
||||
from common.utils import get_logger
|
||||
from .hands import IsSuperUser, IsValidUser, IsSuperUserOrAppUser, \
|
||||
get_user_granted_assets
|
||||
|
@ -34,12 +35,16 @@ from .tasks import update_asset_hardware_info_manual, test_admin_user_connectabi
|
|||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
class AssetViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
class AssetViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||
"""
|
||||
API endpoint that allows Asset to be viewed or edited.
|
||||
"""
|
||||
filter_fields = ("hostname", "ip")
|
||||
search_fields = filter_fields
|
||||
ordering_fields = ("hostname", "ip", "port", "cluster", "type", "env", "cpu_cores")
|
||||
queryset = Asset.objects.all()
|
||||
serializer_class = serializers.AssetSerializer
|
||||
pagination_class = LimitOffsetPagination
|
||||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
|
||||
def get_queryset(self):
|
||||
|
@ -78,7 +83,7 @@ class UserAssetListView(generics.ListAPIView):
|
|||
return queryset
|
||||
|
||||
|
||||
class AssetGroupViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
class AssetGroupViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||
"""
|
||||
Asset group api set, for add,delete,update,list,retrieve resource
|
||||
"""
|
||||
|
@ -112,7 +117,7 @@ class GroupAddAssetsApi(generics.UpdateAPIView):
|
|||
return Response({'error': serializer.errors}, status=400)
|
||||
|
||||
|
||||
class ClusterViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
class ClusterViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||
"""
|
||||
Cluster api set, for add,delete,update,list,retrieve resource
|
||||
"""
|
||||
|
@ -153,7 +158,7 @@ class ClusterAddAssetsApi(generics.UpdateAPIView):
|
|||
return Response({'error': serializer.errors}, status=400)
|
||||
|
||||
|
||||
class AdminUserViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
class AdminUserViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||
"""
|
||||
Admin user api set, for add,delete,update,list,retrieve resource
|
||||
"""
|
||||
|
@ -189,7 +194,7 @@ class SystemUserViewSet(BulkModelViewSet):
|
|||
permission_classes = (IsSuperUserOrAppUser,)
|
||||
|
||||
|
||||
class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
|
||||
class AssetListUpdateApi(CustomFilterMixin, ListBulkCreateUpdateDestroyAPIView):
|
||||
"""
|
||||
Asset bulk update api
|
||||
"""
|
||||
|
|
|
@ -71,10 +71,21 @@ function initTable() {
|
|||
columnDefs: [
|
||||
{targets: 1, createdCell: function (td, cellData, rowData) {
|
||||
{% url 'assets:asset-detail' pk=DEFAULT_PK as the_url %}
|
||||
console.log('{{ the_url }}');
|
||||
var detail_btn = '<a href="{{ the_url }}">' + cellData + '</a>';
|
||||
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', rowData.id));
|
||||
}},
|
||||
{targets: 4, createdCell: function (td, cellData, rowData) {
|
||||
$(td).html(rowData.cluster_name)
|
||||
}},
|
||||
{targets: 5, createdCell: function (td, cellData, rowData) {
|
||||
$(td).html(rowData.get_type_display)
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData, rowData) {
|
||||
$(td).html(rowData.get_env_display)
|
||||
}},
|
||||
{targets: 7, createdCell: function (td, cellData, rowData) {
|
||||
$(td).html(rowData.hardware_info)
|
||||
}},
|
||||
{targets: 8, createdCell: function (td, cellData) {
|
||||
if (!cellData) {
|
||||
$(td).html('<i class="fa fa-times text-danger"></i>')
|
||||
|
@ -98,12 +109,15 @@ function initTable() {
|
|||
}}
|
||||
],
|
||||
ajax_url: '{% url "api-assets:asset-list" %}',
|
||||
columns: [{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" }, {data: "cluster_name"},
|
||||
{data: "get_type_display" }, {data: "get_env_display"}, {data: "hardware_info"},
|
||||
{data: "is_active" }, {data: "is_connective"}, {data: "id" }],
|
||||
columns: [
|
||||
{data: "id"}, {data: "hostname" }, {data: "ip" }, {data: "port" },
|
||||
{data: "cluster"}, {data: "type" }, {data: "env"},
|
||||
{data: "cpu_cores"}, {data: "is_active", orderable: false },
|
||||
{data: "is_connective", orderable: false}, {data: "id", orderable: false }
|
||||
],
|
||||
op_html: $('#actions').html()
|
||||
};
|
||||
return jumpserver.initDataTable(options);
|
||||
return jumpserver.initServerSideDataTable(options);
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
|
|
|
@ -47,8 +47,9 @@ class JSONResponseMixin(object):
|
|||
return JsonResponse(context)
|
||||
|
||||
|
||||
class IDInFilterMixin(object):
|
||||
class CustomFilterMixin(object):
|
||||
def filter_queryset(self, queryset):
|
||||
queryset = super(CustomFilterMixin, self).filter_queryset(queryset)
|
||||
id_list = self.request.query_params.get('id__in')
|
||||
if id_list:
|
||||
import json
|
||||
|
|
|
@ -288,9 +288,17 @@ REST_FRAMEWORK = {
|
|||
'users.authentication.PrivateTokenAuthentication',
|
||||
'users.authentication.SessionAuthentication',
|
||||
),
|
||||
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
|
||||
'DEFAULT_FILTER_BACKENDS': (
|
||||
'django_filters.rest_framework.DjangoFilterBackend',
|
||||
'rest_framework.filters.SearchFilter',
|
||||
'rest_framework.filters.OrderingFilter',
|
||||
),
|
||||
'ORDERING_PARAM': "order",
|
||||
'SEARCH_PARAM': "search",
|
||||
'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S %z',
|
||||
'DATETIME_INPUT_FORMATS': ['%Y-%m-%d %H:%M:%S %z'],
|
||||
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
|
||||
'PAGE_SIZE': 15
|
||||
}
|
||||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
|
|
|
@ -330,6 +330,120 @@ jumpserver.initDataTable = function (options) {
|
|||
return table;
|
||||
};
|
||||
|
||||
jumpserver.initServerSideDataTable = function (options) {
|
||||
// options = {
|
||||
// ele *: $('#dataTable_id'),
|
||||
// ajax_url *: '{% url 'users:user-list-api' %}',
|
||||
// columns *: [{data: ''}, ....],
|
||||
// dom: 'fltip',
|
||||
// i18n_url: '{% static "js/...../en-us.json" %}',
|
||||
// order: [[1, 'asc'], [2, 'asc'], ...],
|
||||
// buttons: ['excel', 'pdf', 'print'],
|
||||
// columnDefs: [{target: 0, createdCell: ()=>{}}, ...],
|
||||
// uc_html: '<a>header button</a>',
|
||||
// op_html: 'div.btn-group?',
|
||||
// paging: true
|
||||
// }
|
||||
var ele = options.ele || $('.dataTable');
|
||||
var columnDefs = [
|
||||
{
|
||||
targets: 0,
|
||||
orderable: false,
|
||||
createdCell: function (td, cellData) {
|
||||
$(td).html('<input type="checkbox" class="text-center ipt_check" id=99991937>'.replace('99991937', cellData));
|
||||
}
|
||||
},
|
||||
{className: 'text-center', targets: '_all'}
|
||||
];
|
||||
columnDefs = options.columnDefs ? options.columnDefs.concat(columnDefs) : columnDefs;
|
||||
var select = {
|
||||
style: 'multi',
|
||||
selector: 'td:first-child'
|
||||
};
|
||||
var table = ele.DataTable({
|
||||
pageLength: options.pageLength || 15,
|
||||
dom: options.dom || '<"#uc.pull-left">flt<"row m-t"<"col-md-8"<"#op.col-md-6"><"col-md-6 text-center"i>><"col-md-4"p>>',
|
||||
order: options.order || [],
|
||||
// select: options.select || 'multi',
|
||||
buttons: [],
|
||||
columnDefs: columnDefs,
|
||||
serverSide: true,
|
||||
processing: true,
|
||||
ajax: {
|
||||
url: options.ajax_url ,
|
||||
data: function (data) {
|
||||
delete data.columns;
|
||||
var length = data.length;
|
||||
if (data.length !== null ){
|
||||
data.limit = data.length;
|
||||
delete data.length;
|
||||
}
|
||||
if (data.start !== null) {
|
||||
data.offset = data.start;
|
||||
delete data.start;
|
||||
}
|
||||
if (data.search !== null) {
|
||||
var search_val = data.search.value;
|
||||
data.search = search_val;
|
||||
}
|
||||
if (data.order !== null && data.order.length === 1) {
|
||||
var col = data.order[0].column;
|
||||
var order = options.columns[col].data;
|
||||
if (data.order[0].dir = "desc") {
|
||||
order = "-" + order;
|
||||
}
|
||||
data.order = order;
|
||||
}
|
||||
},
|
||||
dataSrc: "results"
|
||||
},
|
||||
columns: options.columns || [],
|
||||
select: options.select || select,
|
||||
language: {
|
||||
search: "搜索",
|
||||
lengthMenu: "每页 _MENU_",
|
||||
info: "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项",
|
||||
infoFiltered: "",
|
||||
infoEmpty: "",
|
||||
zeroRecords: "没有匹配项",
|
||||
emptyTable: "没有记录",
|
||||
paginate: {
|
||||
first: "«",
|
||||
previous: "‹",
|
||||
next: "›",
|
||||
last: "»"
|
||||
}
|
||||
},
|
||||
lengthMenu: [[15, 25, 50, -1], [15, 25, 50, "All"]]
|
||||
});
|
||||
table.on('select', function(e, dt, type, indexes) {
|
||||
var $node = table[ type ]( indexes ).nodes().to$();
|
||||
$node.find('input.ipt_check').prop('checked', true);
|
||||
jumpserver.selected[$node.find('input.ipt_check').prop('id')] = true
|
||||
}).on('deselect', function(e, dt, type, indexes) {
|
||||
var $node = table[ type ]( indexes ).nodes().to$();
|
||||
$node.find('input.ipt_check').prop('checked', false);
|
||||
jumpserver.selected[$node.find('input.ipt_check').prop('id')] = false
|
||||
}).
|
||||
on('draw', function(){
|
||||
$('#op').html(options.op_html || '');
|
||||
$('#uc').html(options.uc_html || '');
|
||||
});
|
||||
$('.ipt_check_all').on('click', function() {
|
||||
if (!jumpserver.checked) {
|
||||
$(this).closest('table').find('.ipt_check').prop('checked', true);
|
||||
jumpserver.checked = true;
|
||||
table.rows({search:'applied'}).select();
|
||||
} else {
|
||||
$(this).closest('table').find('.ipt_check').prop('checked', false);
|
||||
jumpserver.checked = false;
|
||||
table.rows({search:'applied'}).deselect();
|
||||
}
|
||||
});
|
||||
|
||||
return table;
|
||||
};
|
||||
|
||||
/**
|
||||
* 替换所有匹配exp的字符串为指定字符串
|
||||
* @param exp 被替换部分的正则
|
||||
|
|
|
@ -13,14 +13,14 @@ from .tasks import write_login_log_async
|
|||
from .models import User, UserGroup
|
||||
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
|
||||
from .utils import check_user_valid, generate_token
|
||||
from common.mixins import IDInFilterMixin
|
||||
from common.mixins import CustomFilterMixin
|
||||
from common.utils import get_logger
|
||||
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class UserViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
class UserViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||
queryset = User.objects.exclude(role="App")
|
||||
# queryset = User.objects.all().exclude(role="App").order_by("date_joined")
|
||||
serializer_class = UserSerializer
|
||||
|
@ -72,7 +72,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
|
|||
user.save()
|
||||
|
||||
|
||||
class UserGroupViewSet(IDInFilterMixin, BulkModelViewSet):
|
||||
class UserGroupViewSet(CustomFilterMixin, BulkModelViewSet):
|
||||
queryset = UserGroup.objects.all()
|
||||
serializer_class = UserGroupSerializer
|
||||
|
||||
|
|
Loading…
Reference in New Issue