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
a04d7725
Commit
a04d7725
authored
Oct 02, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge with master
parents
820d608b
f9b49605
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
799 additions
and
198 deletions
+799
-198
jumpserver.css
apps/static/css/jumpserver.css
+117
-0
awesome-bootstrap-checkbox.css
...awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css
+251
-0
select2.min.css
apps/static/css/plugins/select2/select2.min.css
+0
-0
jumpserver.js
apps/static/js/jumpserver.js
+107
-3
select2.full.min.js
apps/static/js/plugins/select2/select2.full.min.js
+0
-0
_base_list.html
apps/templates/_base_list.html
+3
-0
_head_css_js.html
apps/templates/_head_css_js.html
+0
-8
_modal.html
apps/templates/_modal.html
+2
-2
api.py
apps/users/api.py
+25
-12
models.py
apps/users/models.py
+11
-7
serializers.py
apps/users/serializers.py
+3
-2
_select_user_modal.html
apps/users/templates/users/_select_user_modal.html
+23
-0
_user_bulk_update_modal.html
apps/users/templates/users/_user_bulk_update_modal.html
+37
-0
user_detail.html
apps/users/templates/users/user_detail.html
+2
-2
user_group_detail.html
apps/users/templates/users/user_group_detail.html
+116
-38
user_group_list.html
apps/users/templates/users/user_group_list.html
+1
-1
user_list.html
apps/users/templates/users/user_list.html
+92
-78
urls.py
apps/users/urls.py
+6
-5
utils.py
apps/users/utils.py
+0
-1
views.py
apps/users/views.py
+3
-39
No files found.
apps/static/css/jumpserver.css
View file @
a04d7725
...
...
@@ -78,4 +78,121 @@ th a {
border-top
:
none
!important
;
}
table
.dataTable
tbody
>
tr
.selected
,
table
.dataTable
tbody
>
tr
>
.selected
{
background-color
:
#1ab394
;
}
table
.dataTable
tbody
tr
.selected
a
,
table
.dataTable
tbody
th
.selected
a
,
table
.dataTable
tbody
td
.selected
a
,
table
.dataTable
tbody
tr
.selected
td
i
.text-navy
,
table
.dataTable
tbody
th
.selected
td
i
.text-navy
,
table
.dataTable
tbody
td
.selected
td
i
.text-navy
{
color
:
white
;
}
.m-0
{
margin
:
0px
!important
;
}
.m-t-0
{
margin-top
:
0px
!important
;
}
.m-b-0
{
margin-bottom
:
0px
!important
;
}
.m-l-0
{
margin-left
:
0px
!important
;
}
.m-r-0
{
margin-right
:
0px
!important
;
}
.m-5
{
margin
:
5px
!important
;
}
.m-t-5
{
margin-top
:
5px
!important
;
}
.m-b-5
{
margin-bottom
:
5px
!important
;
}
.m-l-5
{
margin-left
:
5px
!important
;
}
.m-r-5
{
margin-right
:
5px
!important
;
}
.m-10
{
margin
:
10px
!important
;
}
.m-t-10
{
margin-top
:
10px
!important
;
}
.m-b-10
{
margin-bottom
:
10px
!important
;
}
.m-l-10
{
margin-left
:
10px
!important
;
}
.m-r-10
{
margin-right
:
10px
!important
;
}
.m-15
{
margin
:
15px
!important
;
}
.m-t-15
{
margin-top
:
15px
!important
;
}
.m-b-15
{
margin-bottom
:
15px
!important
;
}
.m-l-15
{
margin-left
:
15px
!important
;
}
.m-r-15
{
margin-right
:
15px
!important
;
}
.m-20
{
margin
:
20px
!important
;
}
.m-t-20
{
margin-top
:
20px
!important
;
}
.m-b-20
{
margin-bottom
:
20px
!important
;
}
.m-l-20
{
margin-left
:
20px
!important
;
}
.m-r-20
{
margin-right
:
20px
!important
;
}
.m-25
{
margin
:
25px
!important
;
}
.m-t-25
{
margin-top
:
25px
!important
;
}
.m-b-25
{
margin-bottom
:
25px
!important
;
}
.m-l-25
{
margin-left
:
25px
!important
;
}
.m-r-25
{
margin-right
:
25px
!important
;
}
.m-30
{
margin
:
30px
!important
;
}
.m-t-30
{
margin-top
:
30px
!important
;
}
.m-b-30
{
margin-bottom
:
30px
!important
;
}
.m-l-30
{
margin-left
:
30px
!important
;
}
.m-r-30
{
margin-right
:
30px
!important
;
}
apps/static/css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css
0 → 100644
View file @
a04d7725
.checkbox
{
padding-left
:
20px
;
}
.checkbox
label
{
display
:
inline-block
;
vertical-align
:
middle
;
position
:
relative
;
padding-left
:
5px
;
}
.checkbox
label
::before
{
content
:
""
;
display
:
inline-block
;
position
:
absolute
;
width
:
17px
;
height
:
17px
;
left
:
0
;
margin-left
:
-20px
;
border
:
1px
solid
#cccccc
;
border-radius
:
3px
;
background-color
:
#fff
;
-webkit-transition
:
border
0.15s
ease-in-out
,
color
0.15s
ease-in-out
;
-o-transition
:
border
0.15s
ease-in-out
,
color
0.15s
ease-in-out
;
transition
:
border
0.15s
ease-in-out
,
color
0.15s
ease-in-out
;
}
.checkbox
label
::after
{
display
:
inline-block
;
position
:
absolute
;
width
:
16px
;
height
:
16px
;
left
:
0
;
top
:
0
;
margin-left
:
-20px
;
padding-left
:
3px
;
padding-top
:
1px
;
font-size
:
11px
;
color
:
#555555
;
}
.checkbox
input
[
type
=
"checkbox"
],
.checkbox
input
[
type
=
"radio"
]
{
opacity
:
0
;
z-index
:
1
;
}
.checkbox
input
[
type
=
"checkbox"
]
:focus
+
label
::before
,
.checkbox
input
[
type
=
"radio"
]
:focus
+
label
::before
{
outline
:
thin
dotted
;
outline
:
5px
auto
-webkit-focus-ring-color
;
outline-offset
:
-2px
;
}
.checkbox
input
[
type
=
"checkbox"
]
:checked
+
label
::after
,
.checkbox
input
[
type
=
"radio"
]
:checked
+
label
::after
{
font-family
:
"FontAwesome"
;
content
:
"\f00c"
;
}
.checkbox
input
[
type
=
"checkbox"
]
:disabled
+
label
,
.checkbox
input
[
type
=
"radio"
]
:disabled
+
label
{
opacity
:
0.65
;
}
.checkbox
input
[
type
=
"checkbox"
]
:disabled
+
label
::before
,
.checkbox
input
[
type
=
"radio"
]
:disabled
+
label
::before
{
background-color
:
#eeeeee
;
cursor
:
not-allowed
;
}
.checkbox.checkbox-circle
label
::before
{
border-radius
:
50%
;
}
.checkbox.checkbox-inline
{
margin-top
:
0
;
}
.checkbox-primary
input
[
type
=
"checkbox"
]
:checked
+
label
::before
,
.checkbox-primary
input
[
type
=
"radio"
]
:checked
+
label
::before
{
background-color
:
#337ab7
;
border-color
:
#337ab7
;
}
.checkbox-primary
input
[
type
=
"checkbox"
]
:checked
+
label
::after
,
.checkbox-primary
input
[
type
=
"radio"
]
:checked
+
label
::after
{
color
:
#fff
;
}
.checkbox-danger
input
[
type
=
"checkbox"
]
:checked
+
label
::before
,
.checkbox-danger
input
[
type
=
"radio"
]
:checked
+
label
::before
{
background-color
:
#d9534f
;
border-color
:
#d9534f
;
}
.checkbox-danger
input
[
type
=
"checkbox"
]
:checked
+
label
::after
,
.checkbox-danger
input
[
type
=
"radio"
]
:checked
+
label
::after
{
color
:
#fff
;
}
.checkbox-info
input
[
type
=
"checkbox"
]
:checked
+
label
::before
,
.checkbox-info
input
[
type
=
"radio"
]
:checked
+
label
::before
{
background-color
:
#5bc0de
;
border-color
:
#5bc0de
;
}
.checkbox-info
input
[
type
=
"checkbox"
]
:checked
+
label
::after
,
.checkbox-info
input
[
type
=
"radio"
]
:checked
+
label
::after
{
color
:
#fff
;
}
.checkbox-warning
input
[
type
=
"checkbox"
]
:checked
+
label
::before
,
.checkbox-warning
input
[
type
=
"radio"
]
:checked
+
label
::before
{
background-color
:
#f0ad4e
;
border-color
:
#f0ad4e
;
}
.checkbox-warning
input
[
type
=
"checkbox"
]
:checked
+
label
::after
,
.checkbox-warning
input
[
type
=
"radio"
]
:checked
+
label
::after
{
color
:
#fff
;
}
.checkbox-success
input
[
type
=
"checkbox"
]
:checked
+
label
::before
,
.checkbox-success
input
[
type
=
"radio"
]
:checked
+
label
::before
{
background-color
:
#5cb85c
;
border-color
:
#5cb85c
;
}
.checkbox-success
input
[
type
=
"checkbox"
]
:checked
+
label
::after
,
.checkbox-success
input
[
type
=
"radio"
]
:checked
+
label
::after
{
color
:
#fff
;
}
.radio
{
padding-left
:
20px
;
}
.radio
label
{
display
:
inline-block
;
vertical-align
:
middle
;
position
:
relative
;
padding-left
:
5px
;
}
.radio
label
::before
{
content
:
""
;
display
:
inline-block
;
position
:
absolute
;
width
:
17px
;
height
:
17px
;
left
:
0
;
margin-left
:
-20px
;
border
:
1px
solid
#cccccc
;
border-radius
:
50%
;
background-color
:
#fff
;
-webkit-transition
:
border
0.15s
ease-in-out
;
-o-transition
:
border
0.15s
ease-in-out
;
transition
:
border
0.15s
ease-in-out
;
}
.radio
label
::after
{
display
:
inline-block
;
position
:
absolute
;
content
:
" "
;
width
:
11px
;
height
:
11px
;
left
:
3px
;
top
:
3px
;
margin-left
:
-20px
;
border-radius
:
50%
;
background-color
:
#555555
;
-webkit-transform
:
scale
(
0
,
0
);
-ms-transform
:
scale
(
0
,
0
);
-o-transform
:
scale
(
0
,
0
);
transform
:
scale
(
0
,
0
);
-webkit-transition
:
-webkit-transform
0.1s
cubic-bezier
(
0.8
,
-0.33
,
0.2
,
1.33
);
-moz-transition
:
-moz-transform
0.1s
cubic-bezier
(
0.8
,
-0.33
,
0.2
,
1.33
);
-o-transition
:
-o-transform
0.1s
cubic-bezier
(
0.8
,
-0.33
,
0.2
,
1.33
);
transition
:
transform
0.1s
cubic-bezier
(
0.8
,
-0.33
,
0.2
,
1.33
);
}
.radio
input
[
type
=
"radio"
]
{
opacity
:
0
;
z-index
:
1
;
}
.radio
input
[
type
=
"radio"
]
:focus
+
label
::before
{
outline
:
thin
dotted
;
outline
:
5px
auto
-webkit-focus-ring-color
;
outline-offset
:
-2px
;
}
.radio
input
[
type
=
"radio"
]
:checked
+
label
::after
{
-webkit-transform
:
scale
(
1
,
1
);
-ms-transform
:
scale
(
1
,
1
);
-o-transform
:
scale
(
1
,
1
);
transform
:
scale
(
1
,
1
);
}
.radio
input
[
type
=
"radio"
]
:disabled
+
label
{
opacity
:
0.65
;
}
.radio
input
[
type
=
"radio"
]
:disabled
+
label
::before
{
cursor
:
not-allowed
;
}
.radio.radio-inline
{
margin-top
:
0
;
}
.radio-primary
input
[
type
=
"radio"
]
+
label
::after
{
background-color
:
#337ab7
;
}
.radio-primary
input
[
type
=
"radio"
]
:checked
+
label
::before
{
border-color
:
#337ab7
;
}
.radio-primary
input
[
type
=
"radio"
]
:checked
+
label
::after
{
background-color
:
#337ab7
;
}
.radio-danger
input
[
type
=
"radio"
]
+
label
::after
{
background-color
:
#d9534f
;
}
.radio-danger
input
[
type
=
"radio"
]
:checked
+
label
::before
{
border-color
:
#d9534f
;
}
.radio-danger
input
[
type
=
"radio"
]
:checked
+
label
::after
{
background-color
:
#d9534f
;
}
.radio-info
input
[
type
=
"radio"
]
+
label
::after
{
background-color
:
#5bc0de
;
}
.radio-info
input
[
type
=
"radio"
]
:checked
+
label
::before
{
border-color
:
#5bc0de
;
}
.radio-info
input
[
type
=
"radio"
]
:checked
+
label
::after
{
background-color
:
#5bc0de
;
}
.radio-warning
input
[
type
=
"radio"
]
+
label
::after
{
background-color
:
#f0ad4e
;
}
.radio-warning
input
[
type
=
"radio"
]
:checked
+
label
::before
{
border-color
:
#f0ad4e
;
}
.radio-warning
input
[
type
=
"radio"
]
:checked
+
label
::after
{
background-color
:
#f0ad4e
;
}
.radio-success
input
[
type
=
"radio"
]
+
label
::after
{
background-color
:
#5cb85c
;
}
.radio-success
input
[
type
=
"radio"
]
:checked
+
label
::before
{
border-color
:
#5cb85c
;
}
.radio-success
input
[
type
=
"radio"
]
:checked
+
label
::after
{
background-color
:
#5cb85c
;
}
input
[
type
=
"checkbox"
]
.styled
:checked
+
label
:after
,
input
[
type
=
"radio"
]
.styled
:checked
+
label
:after
{
font-family
:
'FontAwesome'
;
content
:
"\f00c"
;
}
input
[
type
=
"checkbox"
]
.styled
:checked
+
label
::before
,
input
[
type
=
"radio"
]
.styled
:checked
+
label
::before
{
color
:
#fff
;
}
input
[
type
=
"checkbox"
]
.styled
:checked
+
label
::after
,
input
[
type
=
"radio"
]
.styled
:checked
+
label
::after
{
color
:
#fff
;
}
apps/static/css/plugins/select2/select2.min.css
View file @
a04d7725
This diff is collapsed.
Click to expand it.
apps/static/js/jumpserver.js
View file @
a04d7725
...
...
@@ -178,8 +178,8 @@ function activeNav() {
var
url_array
=
document
.
location
.
pathname
.
split
(
"/"
);
var
app
=
url_array
[
1
];
var
resource
=
url_array
[
2
];
if
(
app
==
''
){
$
(
'#index'
).
addClass
(
'active'
)
if
(
app
==
=
''
){
$
(
'#index'
).
addClass
(
'active'
)
;
}
else
{
$
(
"#"
+
app
).
addClass
(
'active'
);
$
(
'#'
+
app
+
' #'
+
resource
).
addClass
(
'active'
);
...
...
@@ -236,8 +236,112 @@ function objectDelete(obj, name, url){
swal
(
'Deleted!'
,
"【"
+
name
+
"】"
+
"has been deleted."
,
"success"
);
$
(
obj
).
parent
().
parent
().
remove
();
}
})
})
;
});
}
$
.
fn
.
serializeObject
=
function
()
{
var
o
=
{};
var
a
=
this
.
serializeArray
();
$
.
each
(
a
,
function
()
{
if
(
o
[
this
.
name
]
!==
undefined
)
{
if
(
!
o
[
this
.
name
].
push
)
{
o
[
this
.
name
]
=
[
o
[
this
.
name
]];
}
o
[
this
.
name
].
push
(
this
.
value
||
''
);
}
else
{
o
[
this
.
name
]
=
this
.
value
||
''
;
}
});
return
o
;
};
var
jumpserver
=
{};
jumpserver
.
checked
=
false
;
jumpserver
.
initDataTable
=
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?'
// }
var
ele
=
options
.
ele
||
$
(
'.dataTable'
);
var
columnDefs
=
[
{
targets
:
0
,
orderable
:
false
,
createdCell
:
function
(
td
)
{
$
(
td
).
html
(
'<div class="checkbox checkbox-default"><input type="checkbox" class="ipt_check"><label></label></div>'
);
}
},
{
className
:
'text-center'
,
targets
:
'_all'
},
];
columnDefs
=
options
.
columnDefs
?
options
.
columnDefs
.
concat
(
columnDefs
)
:
columnDefs
;
var
table
=
ele
.
DataTable
({
pageLength
:
options
.
pageLength
||
25
,
dom
:
options
.
dom
||
'<"#uc.pull-left"><"html5buttons"B>flti<"row m-t"<"#op.col-md-6"><"col-md-6"p>>'
,
language
:
{
url
:
options
.
i18n_url
||
"/static/js/plugins/dataTables/i18n/zh-hans.json"
},
order
:
options
.
order
||
[[
1
,
'asc'
]],
buttons
:
options
.
buttons
||
[
{
extend
:
'excel'
,
exportOptions
:
{
modifier
:
{
selected
:
true
}
}
},
{
extend
:
'pdf'
,
exportOptions
:
{
modifier
:
{
selected
:
true
}
}
},
{
extend
:
'print'
,
customize
:
function
(
win
){
$
(
win
.
document
.
body
).
addClass
(
'white-bg'
);
$
(
win
.
document
.
body
).
css
(
'font-size'
,
'10px'
);
$
(
win
.
document
.
body
).
find
(
'table'
)
.
addClass
(
'compact'
)
.
css
(
'font-size'
,
'inherit'
);
}
}
],
columnDefs
:
columnDefs
,
select
:
options
.
select
||
{
style
:
'multi'
},
ajax
:
{
url
:
options
.
ajax_url
,
dataSrc
:
""
},
columns
:
options
.
columns
||
[]
});
table
.
on
(
'select'
,
function
(
e
,
dt
,
type
,
indexes
)
{
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
$node
.
find
(
'input.ipt_check'
).
prop
(
'checked'
,
true
);
}).
on
(
'deselect'
,
function
(
e
,
dt
,
type
,
indexes
)
{
var
$node
=
table
[
type
](
indexes
).
nodes
().
to$
();
$node
.
find
(
'input.ipt_check'
).
prop
(
'checked'
,
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
().
select
();
}
else
{
$
(
this
).
closest
(
'table'
).
find
(
'.ipt_check'
).
prop
(
'checked'
,
false
);
jumpserver
.
checked
=
false
;
table
.
rows
().
deselect
();
}
})
return
table
;
}
apps/static/js/plugins/select2/select2.full.min.js
View file @
a04d7725
This source diff could not be displayed because it is too large. You can
view the blob
instead.
apps/templates/_base_list.html
View file @
a04d7725
...
...
@@ -3,6 +3,9 @@
{% load common_tags %}
{% block custom_head_css_js %}
<link
href=
"{% static "
css
/
plugins
/
dataTables
/
dataTables
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
awesome-bootstrap-checkbox
/
awesome-bootstrap-checkbox
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
select2
/
select2
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
plugins
/
select2
/
select2
.
full
.
min
.
js
"
%}"
></script>
<script
src=
"{% static "
js
/
plugins
/
dataTables
/
dataTables
.
min
.
js
"
%}"
></script>
{% endblock %}
{% block content %}
...
...
apps/templates/_head_css_js.html
View file @
a04d7725
...
...
@@ -7,17 +7,9 @@
<link
href=
"{% static "
css
/
plugins
/
sweetalert
/
sweetalert
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
style
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
vaildator
/
jquery
.
validator
.
css
"
%}"
rel=
"stylesheet"
>
<!-- scripts -->
<script
src=
"{% static 'js/jquery-2.1.1.js' %}"
></script>
<!-- Sweet alert -->
<script
src=
"{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"
></script>
<script
src=
"{% static 'js/bootstrap.min.js' %}"
></script>
apps/templates/_modal.html
View file @
a04d7725
{% load i18n %}
<div
aria-hidden=
"true"
role=
"dialog"
tabindex=
"-1"
id=
"{% block modal_id %}{% endblock %}"
class=
"modal inmodal"
style=
"display: none;
"
>
<div
class=
"modal-dialog"
>
<div
aria-hidden=
"true"
role=
"dialog"
id=
"{% block modal_id %}{% endblock %}"
class=
"modal inmodal
"
>
<div
class=
"modal-dialog
{% block modal_class %}{% endblock %}
"
>
<div
class=
"modal-content animated fadeIn"
>
<div
class=
"modal-header"
>
<button
data-dismiss=
"modal"
class=
"close"
type=
"button"
><span
aria-hidden=
"true"
>
×
</span><span
class=
"sr-only"
>
Close
</span></button>
...
...
apps/users/api.py
View file @
a04d7725
...
...
@@ -3,10 +3,13 @@
import
logging
from
rest_framework
import
generics
from
django.shortcuts
import
get_object_or_404
from
rest_framework
import
generics
,
status
from
rest_framework.response
import
Response
from
rest_framework_bulk
import
ListBulkCreateUpdateDestroyAPIView
from
.serializers
import
UserSerializer
,
UserGroupSerializer
,
UserAttributeSerializer
,
UserGroup
EditSerializer
,
\
from
.serializers
import
UserSerializer
,
UserGroupSerializer
,
UserAttributeSerializer
,
GroupUser
EditSerializer
,
\
GroupEditSerializer
,
UserPKUpdateSerializer
,
UserBulkUpdateSerializer
from
.models
import
User
,
UserGroup
...
...
@@ -27,11 +30,6 @@ class UserDetailDeleteUpdateApi(generics.RetrieveUpdateDestroyAPIView):
print
(
self
.
request
.
data
)
return
super
(
UserDetailDeleteUpdateApi
,
self
)
.
delete
(
request
,
*
args
,
**
kwargs
)
# def get(self, request, *args, **kwargs):
# print("hello world")
# print(request.user)
# return super(UserDetailDeleteUpdateApi, self).get(request, *args, **kwargs)
class
UserGroupListAddApi
(
generics
.
ListCreateAPIView
):
queryset
=
UserGroup
.
objects
.
all
()
...
...
@@ -48,14 +46,14 @@ class UserAttributeApi(generics.RetrieveUpdateDestroyAPIView):
serializer_class
=
UserAttributeSerializer
class
UserGroup
EditApi
(
generics
.
RetrieveUpdateAPIView
):
class
GroupUser
EditApi
(
generics
.
RetrieveUpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserGroup
EditSerializer
serializer_class
=
GroupUser
EditSerializer
class
UserResetPasswordApi
(
generics
.
UpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserGroup
EditSerializer
serializer_class
=
GroupUser
EditSerializer
def
perform_update
(
self
,
serializer
):
# Note: we are not updating the user object here.
...
...
@@ -70,7 +68,7 @@ class UserResetPasswordApi(generics.UpdateAPIView):
class
UserResetPKApi
(
generics
.
UpdateAPIView
):
queryset
=
User
.
objects
.
all
()
serializer_class
=
UserGroup
EditSerializer
serializer_class
=
GroupUser
EditSerializer
def
perform_update
(
self
,
serializer
):
user
=
self
.
get_object
()
...
...
@@ -90,7 +88,7 @@ class UserUpdatePKApi(generics.UpdateAPIView):
user
.
save
()
class
Group
DeleteApi
(
generics
.
DestroyAPIView
):
class
Group
EditApi
(
generics
.
RetrieveUpdate
DestroyAPIView
):
queryset
=
UserGroup
.
objects
.
all
()
serializer_class
=
GroupEditSerializer
...
...
@@ -111,3 +109,18 @@ class UserBulkUpdateApi(ListBulkCreateUpdateDestroyAPIView):
if
isinstance
(
ids
,
list
):
queryset
=
queryset
.
filter
(
id__in
=
ids
)
return
queryset
class
DeleteUserFromGroupApi
(
generics
.
DestroyAPIView
):
queryset
=
UserGroup
.
objects
.
all
()
serializer_class
=
GroupEditSerializer
def
destroy
(
self
,
request
,
*
args
,
**
kwargs
):
group
=
self
.
get_object
()
self
.
perform_destroy
(
group
,
**
kwargs
)
return
Response
(
status
=
status
.
HTTP_204_NO_CONTENT
)
def
perform_destroy
(
self
,
instance
,
**
kwargs
):
user_id
=
kwargs
.
get
(
'uid'
)
user
=
get_object_or_404
(
User
,
id
=
user_id
)
instance
.
users
.
remove
(
user
)
apps/users/models.py
View file @
a04d7725
...
...
@@ -4,14 +4,14 @@ from __future__ import unicode_literals
from
django.conf
import
settings
from
django.contrib.auth.hashers
import
make_password
from
django.utils
import
timezone
from
django.db
import
models
from
django.contrib.auth.models
import
AbstractUser
from
django.core
import
signing
from
django.db
import
models
,
IntegrityError
from
django.db.models.signals
import
post_save
from
django.dispatch
import
receiver
from
django.db
import
IntegrityError
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.core
import
signing
from
django.utils
import
timezone
from
django.shortcuts
import
reverse
from
rest_framework.authtoken.models
import
Token
...
...
@@ -102,6 +102,9 @@ class User(AbstractUser):
def
password_raw
(
self
,
password_raw_
):
self
.
set_password
(
password_raw_
)
def
get_absolute_url
(
self
):
return
reverse
(
'users:user-detail'
,
args
=
(
self
.
id
,))
@property
def
is_expired
(
self
):
if
self
.
date_expired
>
timezone
.
now
():
...
...
@@ -162,8 +165,9 @@ class User(AbstractUser):
super
(
User
,
self
)
.
save
(
*
args
,
**
kwargs
)
# Add the current user to the default group.
group
=
UserGroup
.
initial
()
self
.
groups
.
add
(
group
)
if
not
self
.
groups
.
count
():
group
=
UserGroup
.
initial
()
self
.
groups
.
add
(
group
)
@property
def
private_token
(
self
):
...
...
@@ -222,7 +226,7 @@ class User(AbstractUser):
user
.
groups
.
add
(
UserGroup
.
initial
())
def
delete
(
self
):
if
self
.
is_superuser
:
if
self
.
pk
==
1
:
return
return
super
(
User
,
self
)
.
delete
()
...
...
apps/users/serializers.py
View file @
a04d7725
...
...
@@ -31,7 +31,7 @@ class GroupEditSerializer(serializers.ModelSerializer):
class
Meta
:
model
=
UserGroup
fields
=
[
'id'
,
'name'
,
'comment'
,
'date_created'
,
'created_by'
]
fields
=
[
'id'
,
'name'
,
'comment'
,
'date_created'
,
'created_by'
,
'users'
]
class
UserAttributeSerializer
(
serializers
.
ModelSerializer
):
...
...
@@ -41,7 +41,7 @@ class UserAttributeSerializer(serializers.ModelSerializer):
fields
=
[
'avatar'
,
'wechat'
,
'phone'
,
'enable_otp'
,
'comment'
,
'is_active'
,
'name'
]
class
UserGroup
EditSerializer
(
serializers
.
ModelSerializer
):
class
GroupUser
EditSerializer
(
serializers
.
ModelSerializer
):
groups
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
UserGroup
.
objects
.
all
())
class
Meta
:
...
...
@@ -73,6 +73,7 @@ class UserPKUpdateSerializer(serializers.ModelSerializer):
class
UserBulkUpdateSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
group_display
=
serializers
.
SerializerMethodField
()
active_display
=
serializers
.
SerializerMethodField
()
groups
=
serializers
.
PrimaryKeyRelatedField
(
many
=
True
,
queryset
=
UserGroup
.
objects
.
all
())
class
Meta
(
object
):
model
=
User
...
...
apps/users/templates/users/_select_user_modal.html
0 → 100644
View file @
a04d7725
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_class %}modal-lg{% endblock %}
{% block modal_id %}select_user_modal{% endblock %}
{% block modal_title%}{% trans "Please Select User" %}{% endblock %}
{% block modal_body %}
<table
class=
"table table-striped table-bordered table-hover "
id=
"select_user_table"
>
<thead>
<tr>
<th
class=
"text-center"
>
<div
class=
"checkbox checkbox-default"
><input
id=
""
type=
"checkbox"
class=
"ipt_check_all"
><label></label></div>
</th>
<th
class=
"text-center"
>
{% trans 'Name' %}
</a></th>
<th
class=
"text-center"
>
{% trans 'Username' %}
</a></th>
<th
class=
"text-center"
>
{% trans 'Role' %}
</th>
<th
class=
"text-center"
>
{% trans 'User group' %}
</th>
<th
class=
"text-center"
>
{% trans 'Asset num' %}
</th>
<th
class=
"text-center"
>
{% trans 'Active' %}
</a></th>
</tr>
</thead>
</table>
{% endblock %}
{% block modal_confirm_id %}btn_select_user{% endblock %}
apps/users/templates/users/_user_bulk_update_modal.html
0 → 100644
View file @
a04d7725
{% extends '_modal.html' %}
{% load i18n %}
{% block modal_id %}user_bulk_update_modal{% endblock %}
{% block modal_title%}{% trans "Update User" %}{% endblock %}
{% block modal_body %}
<p
class=
"text-success text-center"
>
{% trans "Hint: only change the field you want to update." %}
</p>
<form
method=
"post"
class=
"form-horizontal"
action=
""
id=
"fm_user_bulk_update"
>
<div
class=
"form-group"
>
<label
class=
"control-label col-sm-2 col-lg-2 "
for=
"id_role"
>
{% trans "Role" %}
</label>
<div
class=
" col-sm-9 col-lg-9 "
>
<select
class=
" form-control"
id=
"id_role"
name=
"role"
>
<option
value=
""
>
---------
</option>
<option
value=
"Admin"
>
{% trans "Admin" %}
</option>
<option
value=
"User"
>
{% trans "User" %}
</option>
</select>
</div>
</div>
<div
class=
"form-group"
>
<label
for=
"groups"
class=
"col-sm-2 control-label"
>
{% trans 'Groups' %}
</label>
<div
class=
"col-sm-9"
id=
"select2-container"
>
<select
name=
"groups"
id=
"select2_groups"
data-placeholder=
"{% trans 'Select Group' %}"
class=
"select2 form-control m-b"
multiple
>
{% for group in groups %}
<option
value=
"{{ group.id }}"
>
{{ group.name }}
</option>
{% endfor %}
</select>
</div>
</div>
<div
class=
"form-group"
>
<div
class=
"col-sm-9 col-lg-9 col-sm-offset-2"
>
<div
class=
"checkbox checkbox-success"
>
<input
type=
"checkbox"
name=
"enable_otp"
checked
id=
"id_enable_otp"
><label
for=
"id_enable_otp"
>
{% trans 'Enable-OTP' %}
</label>
</div>
</div>
</div>
</form>
{% endblock %}
{% block modal_confirm_id %}btn_user_bulk_update{% endblock %}
apps/users/templates/users/user_detail.html
View file @
a04d7725
...
...
@@ -222,7 +222,7 @@
jumpserver
.
selected_groups
=
{};
function
updateUserGroups
(
user_groups
)
{
var
the_url
=
"{% url 'users:
user-group
-edit-api' pk=user_object.id %}"
;
var
the_url
=
"{% url 'users:
group-user
-edit-api' pk=user_object.id %}"
;
var
body
=
{
id
:
{{
user_object
.
id
}},
groups
:
Object
.
assign
([],
user_groups
)
...
...
@@ -237,7 +237,7 @@ function updateUserGroups(user_groups) {
$
(
'.group_edit tbody'
).
append
(
'<tr>'
+
'<td><b class="bdg_user_group" data-gid="'
+
index
+
'">'
+
group_name
+
'</b></td>'
+
'<td><button class="btn btn-danger btn-
sm
pull-right btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button></td>'
+
'<td><button class="btn btn-danger btn-
xs
pull-right btn_delete_user_group" type="button"><i class="fa fa-minus"></i></button></td>'
+
'</tr>'
)
});
...
...
apps/users/templates/users/user_group_detail.html
View file @
a04d7725
...
...
@@ -5,8 +5,23 @@
{% block custom_head_css_js %}
<link
href=
"{% static "
css
/
plugins
/
select2
/
select2
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
sweetalert
/
sweetalert
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
dataTables
/
dataTables
.
min
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
awesome-bootstrap-checkbox
/
awesome-bootstrap-checkbox
.
css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% static "
js
/
plugins
/
select2
/
select2
.
full
.
min
.
js
"
%}"
></script>
<script
src=
"{% static "
js
/
plugins
/
sweetalert
/
sweetalert
.
min
.
js
"
%}"
></script>
<script
src=
"{% static "
js
/
plugins
/
dataTables
/
dataTables
.
min
.
js
"
%}"
></script>
<style>
.label
{
font-size
:
14px
;
line-height
:
2.5
;
}
.label
.remove
{
color
:
#fff
;
}
.label
span
{
color
:
#5e5e5e
;
}
</style>
{% endblock %}
{% block content %}
<div
class=
"wrapper wrapper-content animated fadeInRight"
>
...
...
@@ -46,9 +61,17 @@
<td><b>
{{ object.comment }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Created at
:
' %}:
</td>
<td>
{% trans 'Created at' %}:
</td>
<td><b>
{{ object.date_created }}
</b></td>
</tr>
<tr>
<td>
{% trans 'Users' %}:
</td>
<td
style=
"line-height: 2"
>
{% for user in object.users.all %}
<span
class=
"label m-l-xs"
><a
href=
"{{ user.get_absolute_url }}"
><span>
{{ user.name }}
</span></a><a
data-uid=
"{{ user.id }}"
class=
"btn_remove"
><i
class=
"remove fa fa-times-circle"
></i></a></span>
{% endfor %}
</td>
</tr>
</table>
</div>
</div>
...
...
@@ -61,43 +84,22 @@
<div
class=
"panel-body"
>
<table
class=
"table"
>
<tbody>
<tr
class=
"no-borders-tr"
>
<td
width=
"50%"
>
{% trans 'Active' %}:
</td>
<td><span
class=
"pull-right"
>
<div
class=
"switch"
>
<div
class=
"onoffswitch"
>
<input
type=
"checkbox"
{%
if
user_object
.
is_active
%}
checked
{%
endif
%}
class=
"onoffswitch-checkbox"
id=
"is_active"
>
<label
class=
"onoffswitch-label"
for=
"is_active"
>
<span
class=
"onoffswitch-inner"
></span>
<span
class=
"onoffswitch-switch"
></span>
</label>
</div>
</div>
</span></td>
</tr>
<tr>
<td>
{% trans 'Enable OTP' %}:
</td>
<td><span
class=
"pull-right"
>
<div
class=
"switch"
>
<div
class=
"onoffswitch"
>
<input
type=
"checkbox"
class=
"onoffswitch-checkbox"
{%
if
user_object
.
enable_otp
%}
checked
{%
endif
%}
id=
"enable_otp"
>
<label
class=
"onoffswitch-label"
for=
"enable_otp"
>
<span
class=
"onoffswitch-inner"
></span>
<span
class=
"onoffswitch-switch"
></span>
</label>
</div>
</div>
</span></td>
</tr>
<tr>
<td>
{% trans 'Reset password' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn_reset_password"
style=
"width: 54px"
>
{% trans 'Reset' %}
</button>
</span>
</td>
</tr>
<tr>
<td>
{% trans 'Add User' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-primary btn-xs"
id=
"btn_group_add_user"
style=
"width: 54px"
data-toggle=
"modal"
data-target=
"#select_user_modal"
>
{% trans 'Add' %}
</button>
</span>
</td>
</tr>
<tr>
<td>
{% trans 'Delete' %}:
</td>
<td>
<span
class=
"pull-right"
>
<button
type=
"button"
class=
"btn btn-danger btn-xs"
id=
"btn_group_delete"
style=
"width: 54px"
>
{% trans 'Delete' %}
</button>
</span>
</td>
</tr>
</tbody>
</table>
</div>
...
...
@@ -108,4 +110,80 @@
</div>
</div>
</div>
{% include "users/_select_user_modal.html" %}
{% endblock %}
{% block custom_foot_js %}
<script>
$
(
document
).
on
(
'click'
,
'.btn_remove'
,
function
(){
var
$this
=
$
(
this
);
var
uid
=
$this
.
data
(
'uid'
);
var
the_url
=
'{% url "users:delete-user-from-group-api" pk=object.id uid=99991937 %}'
.
replace
(
'99991937'
,
uid
);
var
success
=
function
(){
$this
.
closest
(
'.label'
).
remove
();
};
var
error
=
function
(){};
APIUpdateAttr
({
url
:
the_url
,
body
:
"{}"
,
method
:
"DELETE"
,
success
:
success
,
error
:
error
});
return
false
;
}).
on
(
'click'
,
'#btn_group_delete'
,
function
()
{
function
doDelete
()
{
var
the_url
=
'{% url "users:user-group-detail-api" pk=object.id %}'
;
var
success
=
function
()
{
window
.
location
.
href
=
'{% url "users:user-group-list" %}'
;
};
APIUpdateAttr
({
url
:
the_url
,
body
:
"{}"
,
method
:
"DELETE"
,
success
:
success
});
}
swal
({
title
:
"{% trans 'Are you sure?' %}"
,
text
:
"{% trans 'This will delete the current group, but will not delete any user of it.' %}"
,
type
:
"warning"
,
showCancelButton
:
true
,
confirmButtonColor
:
"#DD6B55"
,
confirmButtonText
:
"{% trans 'Confirm' %}"
,
closeOnConfirm
:
false
},
function
()
{
doDelete
();
});
}).
on
(
'shown.bs.modal'
,
'#select_user_modal'
,
function
()
{
if
(
$
.
fn
.
dataTable
.
isDataTable
(
'#select_user_table'
))
{
return
true
;
}
var
options
=
{
ele
:
$
(
'#select_user_table'
),
pageLength
:
10
,
buttons
:
[],
columnDefs
:
[
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}},
],
ajax_url
:
'{% url "users:user-bulk-update-api" %}'
,
columns
:
[{
data
:
function
(){
return
""
}},
{
data
:
"username"
},
{
data
:
"name"
},
{
data
:
"get_role_display"
},
{
data
:
"group_display"
},
{
data
:
function
(){
return
999
}},
{
data
:
"active_display"
}],
};
jumpserver
.
initDataTable
(
options
);
}).
on
(
'click'
,
'#btn_select_user'
,
function
()
{
var
$data_table
=
$
(
'#select_user_table'
).
DataTable
();
var
id_list
=
[];
var
plain_id_list
=
[];
$data_table
.
rows
({
selected
:
true
}).
every
(
function
(){
id_list
.
push
({
id
:
this
.
data
().
id
});
plain_id_list
.
push
(
this
.
data
().
id
);
});
if
(
id_list
===
[])
{
return
false
;
};
console
.
log
(
id_list
);
console
.
log
(
plain_id_list
);
var
body
=
{
id
:
{{
object
.
id
}},
users
:
plain_id_list
.
map
(
Number
)
};
console
.
log
(
body
);
$
(
'#select_user_modal'
).
modal
(
'hide'
);
})
</script>
{% endblock %}
apps/users/templates/users/user_group_list.html
View file @
a04d7725
...
...
@@ -65,7 +65,7 @@ $(document).on('click', '.btn_delete_user_group', function(){
var
$this
=
$
(
this
);
function
doDelete
()
{
var
group_id
=
$this
.
data
(
'gid'
);
var
the_url
=
"{% url 'users:user-group-
delete
-api' 99991937 %}"
.
replace
(
'99991937'
,
group_id
);
var
the_url
=
"{% url 'users:user-group-
edit
-api' 99991937 %}"
.
replace
(
'99991937'
,
group_id
);
var
body
=
{};
var
success
=
function
()
{
var
msg
=
"{% trans 'Group Deleted.' %}"
;
...
...
apps/users/templates/users/user_list.html
View file @
a04d7725
...
...
@@ -2,15 +2,28 @@
{% load i18n static %}
{% get_current_language as LANGUAGE_CODE %}
{% load common_tags %}
{% block content_left_head %}
<a
href=
"{% url 'users:user-create' %}"
class=
"btn btn-sm btn-primary "
>
{% trans "Create user" %}
</a>
{% block custom_head_css_js %}
{{ block.super }}
<style>
div
.dataTables_wrapper
div
.dataTables_filter
,
.dataTables_length
{
float
:
right
!important
;
}
div
.dataTables_wrapper
div
.dataTables_filter
{
margin-left
:
15px
;
}
</style>
{% endblock %}
{% block table_search %}{% endblock %}
{% block table_container %}
<div
class=
"uc pull-left"
><a
href=
"{% url "
users:user-create
"
%}"
class=
"btn btn-sm btn-primary"
>
{% trans "Create user" %}
</a></div>
<table
class=
"table table-striped table-bordered table-hover "
id=
"user_list_table"
>
<thead>
<tr>
<th></th>
<th
class=
"text-center"
>
<div
class=
"checkbox checkbox-default"
><input
id=
""
type=
"checkbox"
class=
"ipt_check_all"
><label></label></div>
</th>
<th
class=
"text-center"
>
{% trans 'Name' %}
</a></th>
<th
class=
"text-center"
>
{% trans 'Username' %}
</a></th>
<th
class=
"text-center"
>
{% trans 'Role' %}
</th>
...
...
@@ -23,93 +36,56 @@
<tbody>
</tbody>
</table>
<div
id=
"actions"
class=
"hide"
>
<div
class=
"input-group"
>
<select
class=
"form-control m-b"
style=
"width: auto"
id=
"slct_bulk_update"
>
<option
value=
"delete"
>
{% trans 'Delete selected' %}
</option>
<option
value=
"update"
>
{% trans 'Update selected' %}
</option>
<option
value=
"deactive"
>
{% trans 'Deactive selected' %}
</option>
</select>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<button
id=
'btn_bulk_update'
style=
"height: 32px;"
class=
"btn btn-sm btn-primary"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% include "users/_user_bulk_update_modal.html" %}
{% endblock %}
{% block content_bottom_left %}
<div
class=
"input-group"
>
<select
class=
"form-control m-b"
style=
"width: auto"
id=
"slct_bulk_update"
>
<option
value=
"delete"
>
{% trans 'Delete selected' %}
</option>
<option
value=
"update"
>
{% trans 'Update selected' %}
</option>
<option
value=
"deactive"
>
{% trans 'Deactive selected' %}
</option>
</select>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<button
id=
'btn_bulk_update'
style=
"height: 32px;"
class=
"btn btn-sm btn-primary"
>
{% trans 'Submit' %}
</button>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script>
$
(
document
).
ready
(
function
(){
$
(
'#user_list_table'
).
DataTable
({
dom
:
'<"html5buttons"B>lftip'
,
language
:
{
url
:
"{% static 'js/plugins/dataTables/i18n/language_code.json' %}"
.
replace
(
'language_code'
,
'{{ LANGUAGE_CODE }}'
)
},
buttons
:
[
{
extend
:
'excel'
,
exportOptions
:
{
modifier
:
{
selected
:
true
}
}
},
{
extend
:
'pdf'
,
exportOptions
:
{
modifier
:
{
selected
:
true
}
}
},
{
extend
:
'print'
,
customize
:
function
(
win
){
$
(
win
.
document
.
body
).
addClass
(
'white-bg'
);
$
(
win
.
document
.
body
).
css
(
'font-size'
,
'10px'
);
$
(
win
.
document
.
body
).
find
(
'table'
)
.
addClass
(
'compact'
)
.
css
(
'font-size'
,
'inherit'
);
}
}
],
var
options
=
{
ele
:
$
(
'#user_list_table'
),
columnDefs
:
[
{
orderable
:
false
,
className
:
'select-checkbox'
,
targets
:
0
},
{
className
:
'text-center'
,
targets
:
[
1
,
2
,
3
,
4
,
5
,
6
,
7
]},
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
detail_btn
=
'<a href="{% url "users:user-detail" pk=99991937 %}">'
+
cellData
+
'</a>'
;
$
(
td
).
html
(
detail_btn
.
replace
(
'99991937'
,
rowData
.
id
));
}},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}},
{
targets
:
7
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
var
update_btn
=
'<a href="{% url "users:user-update" pk=99991937 %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'99991937'
,
cellData
);
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'
.
replace
(
'99991937'
,
cellData
);
if
(
rowData
.
role
===
'Admin'
)
{
if
(
rowData
.
id
===
1
)
{
$
(
td
).
html
(
update_btn
)
}
else
{
$
(
td
).
html
(
update_btn
+
del_btn
)
}
}
},
{
targets
:
6
,
createdCell
:
function
(
td
,
cellData
)
{
if
(
!
cellData
)
{
$
(
td
).
html
(
'<i class="fa fa-times text-danger"></i>'
)
}
else
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}}
],
select
:
{
style
:
'multi'
},
ajax
:
{
url
:
'{% url "users:user-bulk-update-api" %}'
,
dataSrc
:
""
},
columns
:
[
{
data
:
function
(){
return
""
}
},
{
data
:
"name"
},
{
data
:
"username"
},
{
data
:
"get_role_display"
},
{
data
:
"group_display"
},
{
data
:
function
(){
return
999
}
},
{
data
:
"active_display"
},
{
data
:
"id"
}
]
});
}}],
ajax_url
:
'{% url "users:user-bulk-update-api" %}'
,
columns
:
[{
data
:
function
(){
return
""
}},
{
data
:
"username"
},
{
data
:
"name"
},
{
data
:
"get_role_display"
},
{
data
:
"group_display"
},
{
data
:
function
(){
return
999
}},
{
data
:
"active_display"
},
{
data
:
"id"
}],
op_html
:
$
(
'#actions'
).
html
()
};
jumpserver
.
initDataTable
(
options
);
}).
on
(
'click'
,
'#btn_bulk_update'
,
function
(){
var
action
=
$
(
'#slct_bulk_update'
).
val
();
var
$data_table
=
$
(
'#user_list_table'
).
DataTable
()
...
...
@@ -129,6 +105,7 @@ $(document).ready(function(){
});
APIUpdateAttr
({
url
:
the_url
,
method
:
'PATCH'
,
body
:
JSON
.
stringify
(
body
)});
$data_table
.
ajax
.
reload
();
jumpserver
.
checked
=
false
;
}
function
doDelete
()
{
swal
({
...
...
@@ -151,9 +128,12 @@ $(document).ready(function(){
};
var
url_delete
=
the_url
+
'?id__in='
+
JSON
.
stringify
(
plain_id_list
);
APIUpdateAttr
({
url
:
url_delete
,
method
:
'DELETE'
,
success
:
success
,
error
:
fail
});
jumpserver
.
checked
=
false
;
});
}
function
doUpdate
()
{}
function
doUpdate
()
{
$
(
'#user_bulk_update_modal'
).
modal
(
'show'
);
}
switch
(
action
)
{
case
'deactive'
:
doDeactive
();
...
...
@@ -201,6 +181,40 @@ $(document).ready(function(){
},
function
()
{
doDelete
();
});
}).
on
(
'click'
,
'#btn_user_bulk_update'
,
function
(){
var
json_data
=
$
(
'#fm_user_bulk_update'
).
serializeObject
();
var
body
=
{};
body
.
enable_otp
=
(
json_data
.
enable_otp
===
'on'
)?
true
:
false
;
if
(
json_data
.
role
!=
''
)
{
body
.
role
=
json_data
.
role
;
}
if
(
json_data
.
groups
!=
undefined
)
{
body
.
groups
=
json_data
.
groups
;
}
if
(
typeof
body
.
groups
===
'string'
)
{
body
.
groups
=
[
parseInt
(
body
.
groups
)]
}
else
if
(
typeof
body
.
groups
===
'array'
)
{
new_groups
=
body
.
groups
.
map
(
Number
);
body
.
groups
=
new_groups
;
}
var
$data_table
=
$
(
'#user_list_table'
).
DataTable
()
var
post_list
=
[];
$data_table
.
rows
({
selected
:
true
}).
every
(
function
(){
var
content
=
Object
.
assign
({
id
:
this
.
data
().
id
},
body
);
post_list
.
push
(
content
);
});
if
(
post_list
===
[])
{
return
false
;
};
var
the_url
=
"{% url 'users:user-bulk-update-api' %}"
;
var
success
=
function
()
{
var
msg
=
"{% trans 'The selected users has been updated successfully.' %}"
;
swal
(
"{% trans 'User Updated' %}"
,
msg
,
"success"
);
$
(
'#user_list_table'
).
DataTable
().
ajax
.
reload
();
jumpserver
.
checked
=
false
;
}
APIUpdateAttr
({
url
:
the_url
,
method
:
'PATCH'
,
body
:
JSON
.
stringify
(
post_list
),
success
:
success
});
$
(
'#user_bulk_update_modal'
).
modal
(
'hide'
);
})
</script>
{% endblock %}
...
...
apps/users/urls.py
View file @
a04d7725
...
...
@@ -26,7 +26,6 @@ urlpatterns = [
url
(
r'^user/(?P<pk>[0-9]+)/assets-perm$'
,
views
.
UserDetailView
.
as_view
(),
name
=
'user-detail'
),
url
(
r'^user/create$'
,
views
.
UserCreateView
.
as_view
(),
name
=
'user-create'
),
url
(
r'^user/(?P<pk>[0-9]+)/update$'
,
views
.
UserUpdateView
.
as_view
(),
name
=
'user-update'
),
url
(
r'^user/(?P<pk>[0-9]+)/delete$'
,
views
.
UserDeleteView
.
as_view
(),
name
=
'user-delete'
),
url
(
r'^user-group$'
,
views
.
UserGroupListView
.
as_view
(),
name
=
'user-group-list'
),
url
(
r'^user-group/(?P<pk>[0-9]+)$'
,
views
.
UserGroupDetailView
.
as_view
(),
name
=
'user-group-detail'
),
url
(
r'^user-group/create$'
,
views
.
UserGroupCreateView
.
as_view
(),
name
=
'user-group-create'
),
...
...
@@ -47,8 +46,10 @@ urlpatterns += [
url
(
r'^v1/user-groups$'
,
api
.
UserGroupListAddApi
.
as_view
(),
name
=
'user-group-list-api'
),
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)$'
,
api
.
UserGroupDetailDeleteUpdateApi
.
as_view
(),
name
=
'user-group-detail-api'
),
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)/edit$'
,
api
.
UserGroupEditApi
.
as_view
(),
name
=
'user-group-edit-api'
),
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)/delete/$'
,
api
.
GroupDeleteApi
.
as_view
(),
name
=
'user-group-delete-api'
),
url
(
r'^v1/user-groups/(?P<pk>\d+)/user/(?P<uid>\d+)/$'
,
api
.
DeleteUserFromGroupApi
.
as_view
(),
name
=
'delete-user-from-group-api'
),
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)/users/$'
,
api
.
GroupUserEditApi
.
as_view
(),
name
=
'group-user-edit-api'
),
url
(
r'^v1/user-groups/(?P<pk>[0-9]+)/edit/$'
,
api
.
GroupEditApi
.
as_view
(),
name
=
'user-group-edit-api'
),
]
apps/users/utils.py
View file @
a04d7725
...
...
@@ -3,7 +3,6 @@
from
__future__
import
unicode_literals
import
logging
import
os
import
re
from
django.conf
import
settings
from
django.contrib.auth.mixins
import
UserPassesTestMixin
...
...
apps/users/views.py
View file @
a04d7725
...
...
@@ -7,7 +7,6 @@ from django.contrib.auth import login as auth_login, logout as auth_logout
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.contrib.messages.views
import
SuccessMessageMixin
from
django.core.files.storage
import
default_storage
from
django.db.models
import
Q
from
django.http
import
HttpResponseRedirect
from
django.shortcuts
import
reverse
,
redirect
from
django.utils.decorators
import
method_decorator
...
...
@@ -80,27 +79,12 @@ class UserLogoutView(TemplateView):
return
super
(
UserLogoutView
,
self
)
.
get_context_data
(
**
kwargs
)
class
UserListView
(
AdminUserRequiredMixin
,
ListView
):
model
=
User
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
context_object_name
=
'user_list'
template_name
=
'users/asset_permission_list.html'
ordering
=
'-date_joined'
def
get_queryset
(
self
):
self
.
queryset
=
super
(
UserListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
)
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
username__icontains
=
keyword
)
|
Q
(
name__icontains
=
keyword
))
if
sort
:
self
.
queryset
=
self
.
queryset
.
order_by
(
sort
)
return
self
.
queryset
class
UserListView
(
AdminUserRequiredMixin
,
TemplateView
):
template_name
=
'users/user_list.html'
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
UserListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User list'
),
'
keyword'
:
self
.
keyword
})
context
.
update
({
'app'
:
_
(
'Users'
),
'action'
:
_
(
'User list'
),
'
groups'
:
UserGroup
.
objects
.
all
()
})
return
context
...
...
@@ -153,26 +137,6 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView):
return
context
class
UserDeleteView
(
AdminUserRequiredMixin
,
DeleteView
):
model
=
User
success_url
=
reverse_lazy
(
'users:user-list'
)
template_name
=
'users/user_delete_confirm.html'
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
"""
Calls the delete() method on the fetched object and then
redirects to the success URL.
"""
self
.
object
=
self
.
get_object
()
success_url
=
self
.
get_success_url
()
if
self
.
object
.
name
==
"admin"
or
self
.
object
.
id
==
request
.
session
.
get
(
'_auth_user_id'
):
pass
else
:
self
.
object
.
delete
()
return
HttpResponseRedirect
(
success_url
)
class
UserDetailView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
User
template_name
=
'users/user_detail.html'
...
...
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