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
d2197d99
Commit
d2197d99
authored
Sep 26, 2016
by
xiaoyu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix #26
parent
7ab47916
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
290 additions
and
63 deletions
+290
-63
awesome-bootstrap-checkbox.css
...awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css
+251
-0
_base_list.html
apps/templates/_base_list.html
+1
-0
models.py
apps/users/models.py
+1
-1
user_list.html
apps/users/templates/users/user_list.html
+37
-6
utils.py
apps/users/utils.py
+0
-56
No files found.
apps/static/css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css
0 → 100644
View file @
d2197d99
.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/templates/_base_list.html
View file @
d2197d99
...
...
@@ -3,6 +3,7 @@
{% 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"
>
<script
src=
"{% static "
js
/
plugins
/
dataTables
/
dataTables
.
min
.
js
"
%}"
></script>
{% endblock %}
{% block content %}
...
...
apps/users/models.py
View file @
d2197d99
...
...
@@ -216,7 +216,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/templates/users/user_list.html
View file @
d2197d99
...
...
@@ -10,7 +10,9 @@
<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-success"
><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>
...
...
@@ -40,12 +42,14 @@
{% endblock %}
{% block custom_foot_js %}
<script>
jumpserver
.
checked
=
false
;
$
(
document
).
ready
(
function
(){
$
(
'#user_list_table'
).
DataTable
({
var
table
=
$
(
'#user_list_table'
).
DataTable
({
dom
:
'<"html5buttons"B>lftip'
,
language
:
{
url
:
"{% static 'js/plugins/dataTables/i18n/language_code.json' %}"
.
replace
(
'language_code'
,
'{{ LANGUAGE_CODE }}'
)
},
order
:
[[
1
,
'asc'
]],
buttons
:
[
{
extend
:
'excel'
,
exportOptions
:
{
...
...
@@ -72,13 +76,16 @@ $(document).ready(function(){
}
],
columnDefs
:
[
{
orderable
:
false
,
className
:
'select-checkbox'
,
targets
:
0
},
{
className
:
'text-center'
,
targets
:
[
1
,
2
,
3
,
4
,
5
,
6
,
7
]},
{
targets
:
0
,
orderable
:
false
,
createdCell
:
function
(
td
)
{
$
(
td
).
html
(
'<div class="checkbox checkbox-success"><input type="checkbox" class="ipt_check"><label></label></div>'
);
}},
{
className
:
'text-center'
,
targets
:
[
0
,
1
,
2
,
3
,
4
,
5
,
6
,
7
]},
{
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
)
...
...
@@ -92,7 +99,14 @@ $(document).ready(function(){
}
else
{
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}}
}
},
{
targets
:
2
,
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
));
}
}
],
select
:
{
style
:
'multi'
},
ajax
:
{
...
...
@@ -110,6 +124,13 @@ $(document).ready(function(){
{
data
:
"id"
}
]
});
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
(
'click'
,
'#btn_bulk_update'
,
function
(){
var
action
=
$
(
'#slct_bulk_update'
).
val
();
var
$data_table
=
$
(
'#user_list_table'
).
DataTable
()
...
...
@@ -201,6 +222,16 @@ $(document).ready(function(){
},
function
()
{
doDelete
();
});
}).
on
(
'click'
,
'.ipt_check_all'
,
function
(){
if
(
!
jumpserver
.
checked
)
{
$
(
this
).
closest
(
'table'
).
find
(
'.ipt_check'
).
prop
(
'checked'
,
true
);
jumpserver
.
checked
=
true
;
$
(
'#user_list_table'
).
DataTable
().
rows
().
select
();
}
else
{
$
(
this
).
closest
(
'table'
).
find
(
'.ipt_check'
).
prop
(
'checked'
,
false
);
jumpserver
.
checked
=
false
;
$
(
'#user_list_table'
).
DataTable
().
rows
().
deselect
();
}
})
</script>
{% endblock %}
...
...
apps/users/utils.py
View file @
d2197d99
...
...
@@ -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
...
...
@@ -148,58 +147,3 @@ def send_reset_ssh_key_mail(user):
logger
.
debug
(
message
)
send_mail_async
.
delay
(
subject
,
message
,
recipient_list
,
html_message
=
message
)
def
validate_ssh_pk
(
text
):
"""
Expects a SSH private key as string.
Returns a boolean and a error message.
If the text is parsed as private key successfully,
(True,'') is returned. Otherwise,
(False, <message describing the error>) is returned.
from https://github.com/githubnemo/SSH-private-key-validator/blob/master/validate.py
"""
if
not
text
:
return
False
,
'No text given'
startPattern
=
re
.
compile
(
"^-----BEGIN [A-Z]+ PRIVATE KEY-----"
)
optionPattern
=
re
.
compile
(
"^.+: .+"
)
contentPattern
=
re
.
compile
(
"^([a-zA-Z0-9+/]{64}|[a-zA-Z0-9+/]{1,64}[=]{0,2})$"
)
endPattern
=
re
.
compile
(
"^-----END [A-Z]+ PRIVATE KEY-----"
)
def
contentState
(
text
):
for
i
in
range
(
0
,
len
(
text
)):
line
=
text
[
i
]
if
endPattern
.
match
(
line
):
if
i
==
len
(
text
)
-
1
or
len
(
text
[
i
+
1
])
==
0
:
return
True
,
''
else
:
return
False
,
'At end but content coming'
elif
not
contentPattern
.
match
(
line
):
return
False
,
'Wrong string in content section'
return
False
,
'No content or missing end line'
def
optionState
(
text
):
for
i
in
range
(
0
,
len
(
text
)):
line
=
text
[
i
]
if
line
[
-
1
:]
==
'
\\
'
:
return
optionState
(
text
[
i
+
2
:])
if
not
optionPattern
.
match
(
line
):
return
contentState
(
text
[
i
+
1
:])
return
False
,
'Expected option, found nothing'
def
startState
(
text
):
if
len
(
text
)
==
0
or
not
startPattern
.
match
(
text
[
0
]):
return
False
,
'Header is wrong'
return
optionState
(
text
[
1
:])
return
startState
([
n
.
strip
()
for
n
in
text
.
splitlines
()])
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