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 %}
|
||||
{% 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 %}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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()])
|
||||
|
|
Loading…
Reference in New Issue