mirror of https://github.com/jumpserver/jumpserver
fix #26
parent
7ab47916f2
commit
d2197d99c2
|
@ -0,0 +1,251 @@
|
||||||
|
.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;
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
{% load common_tags %}
|
{% load common_tags %}
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<link href="{% static "css/plugins/dataTables/dataTables.min.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/dataTables/dataTables.min.js" %}"></script>
|
<script src="{% static "js/plugins/dataTables/dataTables.min.js" %}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -216,7 +216,7 @@ class User(AbstractUser):
|
||||||
user.groups.add(UserGroup.initial())
|
user.groups.add(UserGroup.initial())
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
if self.is_superuser:
|
if self.pk == 1:
|
||||||
return
|
return
|
||||||
return super(User, self).delete()
|
return super(User, self).delete()
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
<table class="table table-striped table-bordered table-hover " id="user_list_table" >
|
<table class="table table-striped table-bordered table-hover " id="user_list_table" >
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<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 'Name' %}</a></th>
|
||||||
<th class="text-center">{% trans 'Username' %}</a></th>
|
<th class="text-center">{% trans 'Username' %}</a></th>
|
||||||
<th class="text-center">{% trans 'Role' %}</th>
|
<th class="text-center">{% trans 'Role' %}</th>
|
||||||
|
@ -40,12 +42,14 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
|
jumpserver.checked = false;
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$('#user_list_table').DataTable({
|
var table = $('#user_list_table').DataTable({
|
||||||
dom: '<"html5buttons"B>lftip',
|
dom: '<"html5buttons"B>lftip',
|
||||||
language: {
|
language: {
|
||||||
url: "{% static 'js/plugins/dataTables/i18n/language_code.json' %}".replace('language_code', '{{ LANGUAGE_CODE }}')
|
url: "{% static 'js/plugins/dataTables/i18n/language_code.json' %}".replace('language_code', '{{ LANGUAGE_CODE }}')
|
||||||
},
|
},
|
||||||
|
order: [[ 1, 'asc' ]],
|
||||||
buttons: [
|
buttons: [
|
||||||
{extend: 'excel',
|
{extend: 'excel',
|
||||||
exportOptions: {
|
exportOptions: {
|
||||||
|
@ -72,13 +76,16 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
columnDefs: [
|
columnDefs: [
|
||||||
{orderable: false, className: 'select-checkbox', targets: 0},
|
{targets: 0, orderable: false,
|
||||||
{className: 'text-center', targets: [1, 2, 3, 4, 5, 6, 7]},
|
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,
|
{targets: 7,
|
||||||
createdCell: function (td, cellData, rowData) {
|
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 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);
|
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)
|
$(td).html(update_btn)
|
||||||
} else {
|
} else {
|
||||||
$(td).html(update_btn + del_btn)
|
$(td).html(update_btn + del_btn)
|
||||||
|
@ -92,7 +99,14 @@ $(document).ready(function(){
|
||||||
} else {
|
} else {
|
||||||
$(td).html('<i class="fa fa-check text-navy"></i>')
|
$(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'},
|
select: {style: 'multi'},
|
||||||
ajax: {
|
ajax: {
|
||||||
|
@ -110,6 +124,13 @@ $(document).ready(function(){
|
||||||
{data: "id" }
|
{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(){
|
}).on('click', '#btn_bulk_update', function(){
|
||||||
var action = $('#slct_bulk_update').val();
|
var action = $('#slct_bulk_update').val();
|
||||||
var $data_table = $('#user_list_table').DataTable()
|
var $data_table = $('#user_list_table').DataTable()
|
||||||
|
@ -201,6 +222,16 @@ $(document).ready(function(){
|
||||||
}, function() {
|
}, function() {
|
||||||
doDelete();
|
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>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||||
|
@ -148,58 +147,3 @@ def send_reset_ssh_key_mail(user):
|
||||||
logger.debug(message)
|
logger.debug(message)
|
||||||
|
|
||||||
send_mail_async.delay(subject, message, recipient_list, html_message=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()])
|
|
||||||
|
|
Loading…
Reference in New Issue