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
cc18ad9a
Commit
cc18ad9a
authored
Jan 15, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'paging' into dev
parents
8b9e45ad
b2f97a26
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 @
cc18ad9a
...
...
@@ -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 @
cc18ad9a
...
...
@@ -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 @
cc18ad9a
...
...
@@ -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 @
cc18ad9a
...
...
@@ -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 @
cc18ad9a
...
...
@@ -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 @
cc18ad9a
...
...
@@ -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