Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
b2f97a26
Commit
b2f97a26
authored
Jan 15, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Feature] 添加后端paging
parent
59a69f02
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
158 additions
and
16 deletions
+158
-16
api.py
apps/assets/api.py
+11
-6
asset_list.html
apps/assets/templates/assets/asset_list.html
+19
-5
mixins.py
apps/common/mixins.py
+2
-1
settings.py
apps/jumpserver/settings.py
+9
-1
jumpserver.js
apps/static/js/jumpserver.js
+114
-0
api.py
apps/users/api.py
+3
-3
No files found.
apps/assets/api.py
View file @
b2f97a26
...
...
@@ -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
IDIn
FilterMixin
from
common.mixins
import
Custom
FilterMixin
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
(
IDIn
FilterMixin
,
BulkModelViewSet
):
class
AssetViewSet
(
Custom
FilterMixin
,
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
(
IDIn
FilterMixin
,
BulkModelViewSet
):
class
AssetGroupViewSet
(
Custom
FilterMixin
,
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
(
IDIn
FilterMixin
,
BulkModelViewSet
):
class
ClusterViewSet
(
Custom
FilterMixin
,
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
(
IDIn
FilterMixin
,
BulkModelViewSet
):
class
AdminUserViewSet
(
Custom
FilterMixin
,
BulkModelViewSet
):
"""
Admin user api set, for add,delete,update,list,retrieve resource
"""
...
...
@@ -189,7 +194,7 @@ class SystemUserViewSet(BulkModelViewSet):
permission_classes
=
(
IsSuperUserOrAppUser
,)
class
AssetListUpdateApi
(
IDIn
FilterMixin
,
ListBulkCreateUpdateDestroyAPIView
):
class
AssetListUpdateApi
(
Custom
FilterMixin
,
ListBulkCreateUpdateDestroyAPIView
):
"""
Asset bulk update api
"""
...
...
apps/assets/templates/assets/asset_list.html
View file @
b2f97a26
...
...
@@ -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
.
init
ServerSide
DataTable
(
options
);
}
$
(
document
).
ready
(
function
(){
...
...
apps/common/mixins.py
View file @
b2f97a26
...
...
@@ -47,8 +47,9 @@ class JSONResponseMixin(object):
return
JsonResponse
(
context
)
class
IDIn
FilterMixin
(
object
):
class
Custom
FilterMixin
(
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
...
...
apps/jumpserver/settings.py
View file @
b2f97a26
...
...
@@ -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
=
[
...
...
apps/static/js/jumpserver.js
View file @
b2f97a26
...
...
@@ -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 被替换部分的正则
...
...
apps/users/api.py
View file @
b2f97a26
...
...
@@ -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
IDIn
FilterMixin
from
common.mixins
import
Custom
FilterMixin
from
common.utils
import
get_logger
logger
=
get_logger
(
__name__
)
class
UserViewSet
(
IDIn
FilterMixin
,
BulkModelViewSet
):
class
UserViewSet
(
Custom
FilterMixin
,
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
(
IDIn
FilterMixin
,
BulkModelViewSet
):
class
UserGroupViewSet
(
Custom
FilterMixin
,
BulkModelViewSet
):
queryset
=
UserGroup
.
objects
.
all
()
serializer_class
=
UserGroupSerializer
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment