mirror of https://github.com/jumpserver/jumpserver
[Bugfix] 修改了一些issue上的bug
parent
948214cacb
commit
0869931e67
|
@ -6,23 +6,6 @@ from .models import IDC, Asset, AssetGroup, AdminUser, SystemUser, Tag
|
||||||
from common.utils import validate_ssh_private_key, ssh_pubkey_gen
|
from common.utils import validate_ssh_private_key, ssh_pubkey_gen
|
||||||
|
|
||||||
|
|
||||||
# class AssetForm(forms.ModelForm):
|
|
||||||
# class Meta:
|
|
||||||
# model = Asset
|
|
||||||
#
|
|
||||||
# fields = [
|
|
||||||
# 'ip', 'other_ip', 'remote_card_ip', 'hostname', 'port', 'groups', 'username', 'password',
|
|
||||||
# 'idc', 'mac_address', 'brand', 'cpu', 'memory', 'disk', 'os', 'cabinet_no', 'cabinet_pos',
|
|
||||||
# 'number', 'status', 'type', 'env', 'sn', 'is_active', 'comment', 'admin_user', 'system_users'
|
|
||||||
# ]
|
|
||||||
#
|
|
||||||
# widgets = {
|
|
||||||
# 'groups': forms.SelectMultiple(attrs={'class': 'select2-groups', 'data-placeholder': _('Select asset groups')}),
|
|
||||||
# 'system_user': forms.SelectMultiple(attrs={'class': 'select2-system-user', 'data-placeholder': _('Select asset system user')}),
|
|
||||||
# 'admin_user': forms.SelectMultiple(attrs={'class': 'select2-admin-user', 'data-placeholder': _('Select asset admin user')}),
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
|
|
||||||
class AssetCreateForm(forms.ModelForm):
|
class AssetCreateForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
instance = kwargs.get('instance', None)
|
instance = kwargs.get('instance', None)
|
||||||
|
@ -142,15 +125,19 @@ class IDCForm(forms.ModelForm):
|
||||||
|
|
||||||
class AdminUserForm(forms.ModelForm):
|
class AdminUserForm(forms.ModelForm):
|
||||||
# Admin user assets define, let user select, save it in form not in view
|
# Admin user assets define, let user select, save it in form not in view
|
||||||
assets = forms.ModelMultipleChoiceField(queryset=Asset.objects.all(),
|
assets = forms.ModelMultipleChoiceField(
|
||||||
label=_('Asset'),
|
queryset=Asset.objects.all(),
|
||||||
required=False,
|
label=_('Asset'),
|
||||||
widget=forms.SelectMultiple(
|
required=False,
|
||||||
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
widget=forms.SelectMultiple(
|
||||||
)
|
attrs={'class': 'select2', 'data-placeholder': _('Select assets')})
|
||||||
|
)
|
||||||
# Form field name can not start with `_`, so redefine it,
|
# Form field name can not start with `_`, so redefine it,
|
||||||
password = forms.CharField(widget=forms.PasswordInput, max_length=100, min_length=8, strip=True,
|
password = forms.CharField(
|
||||||
help_text=_('If also set private key, use that first'), required=False)
|
widget=forms.PasswordInput, max_length=100,
|
||||||
|
min_length=8, strip=True, required=False,
|
||||||
|
help_text=_('If also set private key, use that first'),
|
||||||
|
)
|
||||||
# Need use upload private key file except paste private key content
|
# Need use upload private key file except paste private key content
|
||||||
private_key_file = forms.FileField(required=False)
|
private_key_file = forms.FileField(required=False)
|
||||||
|
|
||||||
|
@ -173,11 +160,11 @@ class AdminUserForm(forms.ModelForm):
|
||||||
admin_user = super(AdminUserForm, self).save(commit=commit)
|
admin_user = super(AdminUserForm, self).save(commit=commit)
|
||||||
password = self.cleaned_data['password']
|
password = self.cleaned_data['password']
|
||||||
private_key = self.cleaned_data['private_key_file']
|
private_key = self.cleaned_data['private_key_file']
|
||||||
public_key = ssh_pubkey_gen(private_key)
|
|
||||||
|
|
||||||
if password:
|
if password:
|
||||||
admin_user.password = password
|
admin_user.password = password
|
||||||
if private_key:
|
if private_key:
|
||||||
|
public_key = ssh_pubkey_gen(private_key)
|
||||||
admin_user.private_key = private_key
|
admin_user.private_key = private_key
|
||||||
admin_user.public_key = public_key
|
admin_user.public_key = public_key
|
||||||
admin_user.save()
|
admin_user.save()
|
||||||
|
@ -196,8 +183,9 @@ class AdminUserForm(forms.ModelForm):
|
||||||
password = self.cleaned_data['password']
|
password = self.cleaned_data['password']
|
||||||
private_key_file = self.cleaned_data.get('private_key_file', '')
|
private_key_file = self.cleaned_data.get('private_key_file', '')
|
||||||
|
|
||||||
if not (password or private_key_file):
|
if not self.instance and not (password or private_key_file):
|
||||||
raise forms.ValidationError(_('Password and private key file must be input one'))
|
raise forms.ValidationError(
|
||||||
|
_('Password and private key file must be input one'))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AdminUser
|
model = AdminUser
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<div class="ibox-content">
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<form enctype="multipart/form-data" method="post" class="form-horizontal" action="" >
|
<form enctype="multipart/form-data" method="post" class="form-horizontal" action="" >
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.name|bootstrap_horizontal }}
|
{{ form.name|bootstrap_horizontal }}
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'assets:admin-user-update' pk=admin_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:admin-user-update' pk=admin_user.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="pull-right">
|
||||||
|
<a class="btn btn-outline btn-danger btn-delete-admin-user">
|
||||||
|
<i class="fa fa-edit"></i>Delete
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -311,6 +316,38 @@ $(document).ready(function () {
|
||||||
op_html: $('#actions').html()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
jumpserver.initDataTable(options);
|
||||||
|
|
||||||
|
function adminUserDelete(name, url) {
|
||||||
|
function doDelete() {
|
||||||
|
var body = {};
|
||||||
|
var success = function() {
|
||||||
|
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||||
|
window.location.href="{% url 'assets:idc-list' %}";
|
||||||
|
};
|
||||||
|
var fail = function() {
|
||||||
|
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||||
|
};
|
||||||
|
APIUpdateAttr({
|
||||||
|
url: url,
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
method: 'DELETE',
|
||||||
|
success: success,
|
||||||
|
error: fail
|
||||||
|
});
|
||||||
|
}
|
||||||
|
swal({
|
||||||
|
title: 'Are you sure delete ?',
|
||||||
|
text: " [" + name + "] ",
|
||||||
|
type: "warning",
|
||||||
|
showCancelButton: true,
|
||||||
|
cancelButtonText: 'Cancel',
|
||||||
|
confirmButtonColor: "#DD6B55",
|
||||||
|
confirmButtonText: 'Confirm',
|
||||||
|
closeOnConfirm: false
|
||||||
|
}, function () {
|
||||||
|
doDelete()
|
||||||
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
.on('click', '.btn-replace-asset-admin_user', function () {
|
.on('click', '.btn-replace-asset-admin_user', function () {
|
||||||
|
@ -392,8 +429,14 @@ $(document).ready(function () {
|
||||||
var data = {"assets": assets};
|
var data = {"assets": assets};
|
||||||
objectRemove($this, name, the_url, data);
|
objectRemove($this, name, the_url, data);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
}).on('click', '.btn-delete-admin-user', function () {
|
||||||
});
|
var $this = $(this);
|
||||||
|
var name = "{{ admin_user.name }}";
|
||||||
|
var uid = "{{ admin_user.id }}";
|
||||||
|
var the_url = '{% url "api-assets:admin-user-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||||
|
var redirect_url = "{% url 'assets:admin-user-list' %}";
|
||||||
|
objectDelete($this, name, the_url, redirect_url);
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -16,7 +16,6 @@
|
||||||
<div class="panel-options">
|
<div class="panel-options">
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a></li>
|
<li class="active"><a href="" class="text-center"><i class="fa fa-laptop"></i> {% trans 'Detail' %} </a></li>
|
||||||
<li><a href="" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset group perm' %}</a></li>
|
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-group-update' pk=asset_group.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'assets:asset-group-update' pk=asset_group.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -38,12 +38,12 @@
|
||||||
{{ form.address|bootstrap_horizontal }}
|
{{ form.address|bootstrap_horizontal }}
|
||||||
{{ form.contact|bootstrap_horizontal }}
|
{{ form.contact|bootstrap_horizontal }}
|
||||||
{{ form.phone|bootstrap_horizontal }}
|
{{ form.phone|bootstrap_horizontal }}
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<h3 class="widget-head-color-box">IP段</h3>
|
<h3 class="widget-head-color-box">IP段</h3>
|
||||||
{{ form.intranet|bootstrap_horizontal }}
|
{{ form.intranet|bootstrap_horizontal }}
|
||||||
{{ form.extranet|bootstrap_horizontal }}
|
{{ form.extranet|bootstrap_horizontal }}
|
||||||
|
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-4 col-sm-offset-5">
|
<div class="col-sm-4 col-sm-offset-5">
|
||||||
|
|
|
@ -109,7 +109,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
|
|
|
@ -412,35 +412,20 @@ class IDCDeleteView(AdminUserRequiredMixin, DeleteView):
|
||||||
|
|
||||||
class AdminUserListView(AdminUserRequiredMixin, TemplateView):
|
class AdminUserListView(AdminUserRequiredMixin, TemplateView):
|
||||||
model = AdminUser
|
model = AdminUser
|
||||||
# paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
|
||||||
# context_object_name = 'admin_user_list'
|
|
||||||
template_name = 'assets/admin_user_list.html'
|
template_name = 'assets/admin_user_list.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Assets'),
|
'app': _('Assets'),
|
||||||
'action': _('Admin user list'),
|
'action': _('Admin user list'),
|
||||||
# 'keyword': self.request.GET.get('keyword', '')
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super(AdminUserListView, self).get_context_data(**kwargs)
|
return super(AdminUserListView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
# def get_queryset(self):
|
|
||||||
# Todo: Default order by lose asset connection num
|
|
||||||
# self.queryset = super(AdminUserListView, self).get_queryset()
|
|
||||||
# self.keyword = keyword = self.request.GET.get('keyword', '')
|
|
||||||
# self.sort = sort = self.request.GET.get('sort', '-date_created')
|
|
||||||
#
|
|
||||||
# if keyword:
|
|
||||||
# self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
|
|
||||||
# Q(comment__icontains=keyword))
|
|
||||||
#
|
|
||||||
# if sort:
|
|
||||||
# self.queryset = self.queryset.order_by(sort)
|
|
||||||
# return self.queryset
|
|
||||||
|
|
||||||
|
class AdminUserCreateView(AdminUserRequiredMixin,
|
||||||
class AdminUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
SuccessMessageMixin,
|
||||||
|
CreateView):
|
||||||
model = AdminUser
|
model = AdminUser
|
||||||
form_class = forms.AdminUserForm
|
form_class = forms.AdminUserForm
|
||||||
template_name = 'assets/admin_user_create_update.html'
|
template_name = 'assets/admin_user_create_update.html'
|
||||||
|
@ -455,11 +440,12 @@ class AdminUserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateVie
|
||||||
return super(AdminUserCreateView, self).get_context_data(**kwargs)
|
return super(AdminUserCreateView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
def get_success_message(self, cleaned_data):
|
||||||
success_message = _('Create admin user <a href="%s">%s</a> successfully.' %
|
success_message = _(
|
||||||
(
|
'Create admin user <a href="%s">%s</a> successfully.' % (
|
||||||
reverse_lazy('assets:admin-user-detail', kwargs={'pk': self.object.pk}),
|
reverse_lazy('assets:admin-user-detail',
|
||||||
self.object.name,
|
kwargs={'pk': self.object.pk}),
|
||||||
))
|
self.object.name,
|
||||||
|
))
|
||||||
return success_message
|
return success_message
|
||||||
|
|
||||||
def form_invalid(self, form):
|
def form_invalid(self, form):
|
||||||
|
@ -480,7 +466,8 @@ class AdminUserUpdateView(AdminUserRequiredMixin, UpdateView):
|
||||||
return super(AdminUserUpdateView, self).get_context_data(**kwargs)
|
return super(AdminUserUpdateView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
success_url = reverse_lazy('assets:admin-user-detail', pk=self.object.pk)
|
success_url = reverse_lazy('assets:admin-user-detail',
|
||||||
|
kwargs={'pk': self.object.pk})
|
||||||
return success_url
|
return success_url
|
||||||
|
|
||||||
|
|
||||||
|
@ -787,7 +774,7 @@ class AssetExportView(View):
|
||||||
return HttpResponse('Json object not valid', status=400)
|
return HttpResponse('Json object not valid', status=400)
|
||||||
spm = uuid.uuid4().get_hex()
|
spm = uuid.uuid4().get_hex()
|
||||||
cache.set(spm, assets_id, 300)
|
cache.set(spm, assets_id, 300)
|
||||||
url = reverse('assets:asset-export') + '?spm=%s' % spm
|
url = reverse_lazy('assets:asset-export') + '?spm=%s' % spm
|
||||||
return JsonResponse({'redirect': url})
|
return JsonResponse({'redirect': url})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('table').DataTable({
|
$('table').DataTable({
|
||||||
"searching": false,
|
"searching": false,
|
||||||
|
"bInfo" : false,
|
||||||
"paging": false,
|
"paging": false,
|
||||||
"order": []
|
"order": []
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,17 +24,17 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<select class="select2 form-control" name="username">
|
<select class="select2 form-control" name="username">
|
||||||
<option value="">{% trans 'Select user' %}</option>
|
<option value="">{% trans 'User' %}</option>
|
||||||
{% for user in user_list %}
|
{% for user in user_list %}
|
||||||
<option value="{{ user.username }}" {% if user.username == username %} selected {% endif %}>{{ user.username }}</option>
|
<option value="{{ user }}" {% if user == username %} selected {% endif %}>{{ user }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<select class="select2 form-control" name="ip">
|
<select class="select2 form-control" name="ip">
|
||||||
<option value="">{% trans 'Select asset' %}</option>
|
<option value="">{% trans 'Asset' %}</option>
|
||||||
{% for asset in asset_list %}
|
{% for asset in asset_list %}
|
||||||
<option value="{{ asset.ip }}" {% if asset.ip == ip %} selected {% endif %}>{{ asset.ip }}</option>
|
<option value="{{ asset }}" {% if asset == ip %} selected {% endif %}>{{ asset }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -42,12 +42,12 @@
|
||||||
<select class="select2 form-control" name="system_user">
|
<select class="select2 form-control" name="system_user">
|
||||||
<option value="">{% trans 'System user' %}</option>
|
<option value="">{% trans 'System user' %}</option>
|
||||||
{% for su in system_user_list %}
|
{% for su in system_user_list %}
|
||||||
<option value="{{ su.username }}" {% if su.username == system_user %} selected {% endif %}>{{ su.username }}</option>
|
<option value="{{ su }}" {% if su == system_user %} selected {% endif %}>{{ su }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
|
<input type="text" class="form-control input-sm" name="keyword" placeholder="Command" value="{{ keyword }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="input-group-btn">
|
<div class="input-group-btn">
|
||||||
|
@ -108,6 +108,7 @@
|
||||||
$('table').DataTable({
|
$('table').DataTable({
|
||||||
"searching": false,
|
"searching": false,
|
||||||
"paging": false,
|
"paging": false,
|
||||||
|
"bInfo" : false,
|
||||||
"order": []
|
"order": []
|
||||||
});
|
});
|
||||||
$('.select2').select2();
|
$('.select2').select2();
|
||||||
|
|
|
@ -18,6 +18,9 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
||||||
model = ProxyLog
|
model = ProxyLog
|
||||||
template_name = 'audits/proxy_log_list.html'
|
template_name = 'audits/proxy_log_list.html'
|
||||||
context_object_name = 'proxy_log_list'
|
context_object_name = 'proxy_log_list'
|
||||||
|
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||||
|
|
||||||
|
keyword = username = ip = system_user = date_from_s = date_to_s = ''
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
date_now = timezone.localtime(timezone.now())
|
date_now = timezone.localtime(timezone.now())
|
||||||
|
@ -46,20 +49,24 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
||||||
if system_user:
|
if system_user:
|
||||||
self.queryset = self.queryset.filter(system_user=system_user)
|
self.queryset = self.queryset.filter(system_user=system_user)
|
||||||
if keyword:
|
if keyword:
|
||||||
self.queryset = self.queryset.filter(Q(username__contains=keyword) |
|
self.queryset = self.queryset.filter(
|
||||||
Q(name__icontains=keyword) |
|
Q(username__contains=keyword) |
|
||||||
Q(hostname__icontains=keyword) |
|
Q(name__icontains=keyword) |
|
||||||
Q(ip__icontains=keyword) |
|
Q(hostname__icontains=keyword) |
|
||||||
Q(system_user__icontains=keyword)).distinct()
|
Q(ip__icontains=keyword) |
|
||||||
|
Q(system_user__icontains=keyword)).distinct()
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': _('Audits'),
|
'app': _('Audits'),
|
||||||
'action': _('Proxy log list'),
|
'action': _('Proxy log list'),
|
||||||
'user_list': User.objects.all().order_by('username'),
|
'user_list': set(
|
||||||
'asset_list': Asset.objects.all().order_by('ip'),
|
list(ProxyLog.objects.values_list('username', flat=True))),
|
||||||
'system_user_list': SystemUser.objects.all().order_by('name'),
|
'asset_list': set(
|
||||||
|
list(ProxyLog.objects.values_list('ip', flat=True))),
|
||||||
|
'system_user_list': set(
|
||||||
|
list(ProxyLog.objects.values_list('system_user', flat=True))),
|
||||||
'keyword': self.keyword,
|
'keyword': self.keyword,
|
||||||
'date_from': self.date_from_s,
|
'date_from': self.date_from_s,
|
||||||
'date_to': self.date_to_s,
|
'date_to': self.date_to_s,
|
||||||
|
@ -71,9 +78,12 @@ class ProxyLogListView(AdminUserRequiredMixin, ListView):
|
||||||
return super(ProxyLogListView, self).get_context_data(**kwargs)
|
return super(ProxyLogListView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
class ProxyLogDetailView(AdminUserRequiredMixin,
|
||||||
|
SingleObjectMixin,
|
||||||
|
ListView):
|
||||||
template_name = 'audits/proxy_log_detail.html'
|
template_name = 'audits/proxy_log_detail.html'
|
||||||
context_object_name = 'proxy_log'
|
context_object_name = 'proxy_log'
|
||||||
|
object = ''
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
||||||
|
@ -91,12 +101,16 @@ class ProxyLogDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||||
return super(ProxyLogDetailView, self).get_context_data(**kwargs)
|
return super(ProxyLogDetailView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogCommandsListView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
class ProxyLogCommandsListView(AdminUserRequiredMixin,
|
||||||
|
SingleObjectMixin,
|
||||||
|
ListView):
|
||||||
template_name = 'audits/proxy_log_commands_list_modal.html'
|
template_name = 'audits/proxy_log_commands_list_modal.html'
|
||||||
|
object = ''
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
||||||
return super(ProxyLogCommandsListView, self).get(request, *args, **kwargs)
|
return super(ProxyLogCommandsListView, self).\
|
||||||
|
get(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return list(self.object.command_log.all())
|
return list(self.object.command_log.all())
|
||||||
|
@ -107,6 +121,7 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
|
||||||
template_name = 'audits/command_log_list.html'
|
template_name = 'audits/command_log_list.html'
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||||
context_object_name = 'command_list'
|
context_object_name = 'command_list'
|
||||||
|
keyword = username = ip = system_user = date_from_s = date_to_s = ''
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
date_now = timezone.localtime(timezone.now())
|
date_now = timezone.localtime(timezone.now())
|
||||||
|
@ -114,29 +129,30 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
|
||||||
seven_days_ago_s = (date_now-timezone.timedelta(7)).strftime('%m/%d/%Y')
|
seven_days_ago_s = (date_now-timezone.timedelta(7)).strftime('%m/%d/%Y')
|
||||||
self.queryset = super(CommandLogListView, self).get_queryset()
|
self.queryset = super(CommandLogListView, self).get_queryset()
|
||||||
self.keyword = keyword = self.request.GET.get('keyword', '')
|
self.keyword = keyword = self.request.GET.get('keyword', '')
|
||||||
self.sort = sort = self.request.GET.get('sort', '-datetime')
|
|
||||||
self.username = username = self.request.GET.get('username', '')
|
self.username = username = self.request.GET.get('username', '')
|
||||||
self.ip = ip = self.request.GET.get('ip', '')
|
self.ip = ip = self.request.GET.get('ip', '')
|
||||||
self.system_user = system_user = self.request.GET.get('system_user', '')
|
self.system_user = system_user = self.request.GET.get('system_user', '')
|
||||||
self.date_from_s = date_from_s = self.request.GET.get('date_from', '%s' % seven_days_ago_s)
|
self.date_from_s = date_from_s = \
|
||||||
self.date_to_s = date_to_s = self.request.GET.get('date_to', '%s' % now_s)
|
self.request.GET.get('date_from', '%s' % seven_days_ago_s)
|
||||||
|
self.date_to_s = date_to_s = \
|
||||||
|
self.request.GET.get('date_to', '%s' % now_s)
|
||||||
|
|
||||||
if date_from_s:
|
if date_from_s:
|
||||||
date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
|
date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
|
||||||
self.queryset = self.queryset.filter(datetime__gt=date_from)
|
self.queryset = self.queryset.filter(datetime__gt=date_from)
|
||||||
if date_to_s:
|
if date_to_s:
|
||||||
date_to = timezone.datetime.strptime(date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
|
date_to = timezone.datetime.strptime(
|
||||||
|
date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
|
||||||
self.queryset = self.queryset.filter(datetime__lt=date_to)
|
self.queryset = self.queryset.filter(datetime__lt=date_to)
|
||||||
if username:
|
if username:
|
||||||
self.queryset = self.queryset.filter(proxy_log__username=username)
|
self.queryset = self.queryset.filter(proxy_log__username=username)
|
||||||
if ip:
|
if ip:
|
||||||
self.queryset = self.queryset.filter(proxy_log__ip=ip)
|
self.queryset = self.queryset.filter(proxy_log__ip=ip)
|
||||||
if system_user:
|
if system_user:
|
||||||
self.queryset = self.queryset.filter(proxy_log__system_user=system_user)
|
self.queryset = self.queryset.filter(
|
||||||
|
proxy_log__system_user=system_user)
|
||||||
if keyword:
|
if keyword:
|
||||||
self.queryset = self.queryset.filter(command=keyword)
|
self.queryset = self.queryset.filter(command=keyword)
|
||||||
if sort:
|
|
||||||
self.queryset = self.queryset.order_by(sort)
|
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
@ -159,31 +175,39 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
|
||||||
|
|
||||||
class LoginLogListView(AdminUserRequiredMixin, ListView):
|
class LoginLogListView(AdminUserRequiredMixin, ListView):
|
||||||
model = LoginLog
|
model = LoginLog
|
||||||
|
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
||||||
template_name = 'audits/login_log_list.html'
|
template_name = 'audits/login_log_list.html'
|
||||||
context_object_name = 'login_log_list'
|
context_object_name = 'login_log_list'
|
||||||
|
|
||||||
|
keyword = username = date_from_s = date_to_s = ''
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
date_now = timezone.localtime(timezone.now())
|
date_now = timezone.localtime(timezone.now())
|
||||||
now_s = date_now.strftime('%m/%d/%Y')
|
now_s = date_now.strftime('%m/%d/%Y')
|
||||||
seven_days_ago_s = (date_now - timezone.timedelta(7)).strftime('%m/%d/%Y')
|
seven_days_ago_s = (date_now - timezone.timedelta(7))\
|
||||||
|
.strftime('%m/%d/%Y')
|
||||||
self.queryset = super(LoginLogListView, self).get_queryset()
|
self.queryset = super(LoginLogListView, self).get_queryset()
|
||||||
self.keyword = keyword = self.request.GET.get('keyword', '')
|
self.keyword = keyword = self.request.GET.get('keyword', '')
|
||||||
self.username = username = self.request.GET.get('username', '')
|
self.username = username = self.request.GET.get('username', '')
|
||||||
self.date_from_s = date_from_s = self.request.GET.get('date_from', '%s' % seven_days_ago_s)
|
self.date_from_s = date_from_s = self.request.GET.get(
|
||||||
self.date_to_s = date_to_s = self.request.GET.get('date_to', '%s' % now_s)
|
'date_from', '%s' % seven_days_ago_s)
|
||||||
|
self.date_to_s = date_to_s = self.request.GET.get(
|
||||||
|
'date_to', '%s' % now_s)
|
||||||
|
|
||||||
if date_from_s:
|
if date_from_s:
|
||||||
date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
|
date_from = timezone.datetime.strptime(date_from_s, '%m/%d/%Y')
|
||||||
self.queryset = self.queryset.filter(date_login__gt=date_from)
|
self.queryset = self.queryset.filter(date_login__gt=date_from)
|
||||||
if date_to_s:
|
if date_to_s:
|
||||||
date_to = timezone.datetime.strptime(date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
|
date_to = timezone.datetime.strptime(
|
||||||
|
date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S')
|
||||||
self.queryset = self.queryset.filter(date_login__lt=date_to)
|
self.queryset = self.queryset.filter(date_login__lt=date_to)
|
||||||
if username:
|
if username:
|
||||||
self.queryset = self.queryset.filter(username=username)
|
self.queryset = self.queryset.filter(username=username)
|
||||||
if keyword:
|
if keyword:
|
||||||
self.queryset = self.queryset.filter(Q(username__contains=keyword) |
|
self.queryset = self.queryset.filter(
|
||||||
Q(name__icontains=keyword) |
|
Q(username__contains=keyword) |
|
||||||
Q(login_ip=keyword)).distinct()
|
Q(name__icontains=keyword) |
|
||||||
|
Q(login_ip=keyword)).distinct()
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
|
|
@ -26,16 +26,21 @@ class AssetPermissionForm(forms.ModelForm):
|
||||||
'system_users', 'is_active', 'date_expired', 'comment',
|
'system_users', 'is_active', 'date_expired', 'comment',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'users': forms.SelectMultiple(attrs={'class': 'select2',
|
'users': forms.SelectMultiple(
|
||||||
'data-placeholder': _('Select users')}),
|
attrs={'class': 'select2',
|
||||||
'user_groups': forms.SelectMultiple(attrs={'class': 'select2',
|
'data-placeholder': _('Select users')}),
|
||||||
'data-placeholder': _('Select user groups')}),
|
'user_groups': forms.SelectMultiple(
|
||||||
'assets': forms.SelectMultiple(attrs={'class': 'select2',
|
attrs={'class': 'select2',
|
||||||
'data-placeholder': _('Select assets')}),
|
'data-placeholder': _('Select user groups')}),
|
||||||
'asset_groups': forms.SelectMultiple(attrs={'class': 'select2',
|
'assets': forms.SelectMultiple(
|
||||||
'data-placeholder': _('Select asset groups')}),
|
attrs={'class': 'select2',
|
||||||
'system_users': forms.SelectMultiple(attrs={'class': 'select2',
|
'data-placeholder': _('Select assets')}),
|
||||||
'data-placeholder': _('Select system users')}),
|
'asset_groups': forms.SelectMultiple(
|
||||||
|
attrs={'class': 'select2',
|
||||||
|
'data-placeholder': _('Select asset groups')}),
|
||||||
|
'system_users': forms.SelectMultiple(
|
||||||
|
attrs={'class': 'select2',
|
||||||
|
'data-placeholder': _('Select system users')}),
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': '* required',
|
'name': '* required',
|
||||||
|
|
|
@ -31,6 +31,11 @@
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="pull-right">
|
||||||
|
<a class="btn btn-outline btn-danger btn-delete-perm">
|
||||||
|
<i class="fa fa-edit"></i>Delete
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -191,25 +196,15 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
{# function switch_user_status(obj) {#}
|
|
||||||
{# var status = $(obj).prop('checked');#}
|
|
||||||
{##}
|
|
||||||
{# $.ajax({#}
|
|
||||||
{# url: "{% url 'users:user-active-api' pk=user.id %}",#}
|
|
||||||
{# type: "PUT",#}
|
|
||||||
{# data: {#}
|
|
||||||
{# 'is_active': status#}
|
|
||||||
{# },#}
|
|
||||||
{# success: function (data, status) {#}
|
|
||||||
{# console.log(data)#}
|
|
||||||
{# },#}
|
|
||||||
{# error: function () {#}
|
|
||||||
{# console.log('error')#}
|
|
||||||
{# }#}
|
|
||||||
{# })#}
|
|
||||||
{# }#}
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.select2').select2();
|
$('.select2').select2();
|
||||||
});
|
}).on('click', '.btn-delete-perm', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = "{{ asset_permission.name }}";
|
||||||
|
var uid = "{{ asset_permission.id }}";
|
||||||
|
var the_url = '{% url "api-perms:asset-permission-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||||
|
var redirect_url = "{% url 'perms:asset-permission-list' %}";
|
||||||
|
objectDelete($this, name, the_url, redirect_url);
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -2,7 +2,9 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load common_tags %}
|
{% load common_tags %}
|
||||||
{% block content_left_head %}
|
{% block content_left_head %}
|
||||||
<a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary "> {% trans "Create permission" %} </a>
|
<a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary">
|
||||||
|
{% trans "Create permission" %}
|
||||||
|
</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block table_head %}
|
{% block table_head %}
|
||||||
|
@ -39,8 +41,12 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}" class="btn btn-xs btn-info">{% trans 'Update' %}</a>
|
<a href="{% url 'perms:asset-permission-update' pk=asset_permission.id %}"
|
||||||
<a href="{% url 'perms:asset-permission-delete' pk=asset_permission.id %}" class="btn btn-xs btn-danger del">{% trans 'Delete' %}</a>
|
class="btn btn-xs btn-info">{% trans 'Update' %}
|
||||||
|
</a>
|
||||||
|
<a class="btn btn-xs btn-danger btn-del" data-name="{{ asset_permission.name }}"
|
||||||
|
data-uid="{{ asset_permission.id }}">{% trans 'Delete' %}
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -54,6 +60,13 @@
|
||||||
"paging": false,
|
"paging": false,
|
||||||
"order": []
|
"order": []
|
||||||
})
|
})
|
||||||
|
}).on('click', '.btn-del', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = $this.data('name');
|
||||||
|
var uid = $this.data('uid');
|
||||||
|
var the_url = '{% url "api-perms:asset-permission-detail" pk=99991937 %}'
|
||||||
|
.replace('99991937', uid);
|
||||||
|
objectDelete($this, name, the_url);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -213,12 +213,16 @@ function APIUpdateAttr(props) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sweet Alert for Delete
|
// Sweet Alert for Delete
|
||||||
function objectDelete(obj, name, url) {
|
function objectDelete(obj, name, url, redirectTo) {
|
||||||
function doDelete() {
|
function doDelete() {
|
||||||
var body = {};
|
var body = {};
|
||||||
var success = function() {
|
var success = function() {
|
||||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||||
$(obj).parent().parent().remove();
|
if (!redirectTo) {
|
||||||
|
$(obj).parent().parent().remove();
|
||||||
|
} else {
|
||||||
|
window.location.href=redirectTo;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
var fail = function() {
|
var fail = function() {
|
||||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{% if is_paginated %}
|
{% if is_paginated %}
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<div class="dataTables_info text-center" id="editable_info" role="status" aria-live="polite">
|
<div class="dataTables_info text-center" id="editable_info" role="status" aria-live="polite">
|
||||||
{{ page_obj.start_index }} - {{ page_obj.end_index }} of {{ paginator.count }}
|
显示第 {{ page_obj.start_index }} 至 {{ page_obj.end_index }} 项结果,共 {{ paginator.count }} 项
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
|
|
|
@ -33,8 +33,9 @@ class UserGroup(NoDeleteModelMixin, Group):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def initial(cls):
|
def initial(cls):
|
||||||
group, created = cls.objects.get_or_create(name='Default', comment='Default user group for all user',
|
group, created = cls.objects.get_or_create(
|
||||||
created_by='System')
|
name='Default', created_by='System',
|
||||||
|
comment='Default user group for all user')
|
||||||
return group
|
return group
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -3,49 +3,54 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load bootstrap %}
|
{% load bootstrap %}
|
||||||
{% block form %}
|
{% block form %}
|
||||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
{% if form.non_field_errors %}
|
||||||
{% csrf_token %}
|
<div class="alert alert-danger">
|
||||||
<h3>{% trans 'Account' %}</h3>
|
{{ form.non_field_errors }}
|
||||||
{{ form.username|bootstrap_horizontal }}
|
|
||||||
{{ form.name|bootstrap_horizontal }}
|
|
||||||
{{ form.email|bootstrap_horizontal }}
|
|
||||||
{{ form.groups|bootstrap_horizontal }}
|
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
|
||||||
{% block password %} {% endblock %}
|
|
||||||
|
|
||||||
<div class="hr-line-dashed"></div>
|
|
||||||
<h3>{% trans 'Security and Role' %}</h3>
|
|
||||||
{{ form.role|bootstrap_horizontal }}
|
|
||||||
<div class="form-group {% if form.date_expired.errors %} has-error {% endif %}" id="date_5">
|
|
||||||
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<div class="input-group date">
|
|
||||||
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
|
||||||
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d' }}">
|
|
||||||
</div>
|
|
||||||
<span class="help-block ">{{ form.date_expired.errors }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
{{ form.enable_otp }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="hr-line-dashed"></div>
|
{% endif %}
|
||||||
<h3>{% trans 'Profile' %}</h3>
|
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||||
{{ form.phone|bootstrap_horizontal }}
|
{% csrf_token %}
|
||||||
{{ form.wechat|bootstrap_horizontal }}
|
<h3>{% trans 'Account' %}</h3>
|
||||||
{{ form.comment|bootstrap_horizontal }}
|
{{ form.username|bootstrap_horizontal }}
|
||||||
<div class="hr-line-dashed"></div>
|
{{ form.name|bootstrap_horizontal }}
|
||||||
<div class="form-group">
|
{{ form.email|bootstrap_horizontal }}
|
||||||
<div class="col-sm-4 col-sm-offset-2">
|
{{ form.groups|bootstrap_horizontal }}
|
||||||
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
|
|
||||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
<div class="hr-line-dashed"></div>
|
||||||
</div>
|
{% block password %} {% endblock %}
|
||||||
|
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<h3>{% trans 'Security and Role' %}</h3>
|
||||||
|
{{ form.role|bootstrap_horizontal }}
|
||||||
|
<div class="form-group {% if form.date_expired.errors %} has-error {% endif %}" id="date_5">
|
||||||
|
<label for="{{ form.date_expired.id_for_label }}" class="col-sm-2 control-label">{{ form.date_expired.label }}</label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group date">
|
||||||
|
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
||||||
|
<input id="{{ form.date_expired.id_for_label }}" name="{{ form.date_expired.html_name }}" type="text" class="form-control" value="{{ form.date_expired.value|date:'Y-m-d' }}">
|
||||||
|
</div>
|
||||||
|
<span class="help-block ">{{ form.date_expired.errors }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<div class="form-group">
|
||||||
|
<label for="{{ form.enable_otp.id_for_label }}" class="col-sm-2 control-label">{% trans 'Enable OTP' %}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
{{ form.enable_otp }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<h3>{% trans 'Profile' %}</h3>
|
||||||
|
{{ form.phone|bootstrap_horizontal }}
|
||||||
|
{{ form.wechat|bootstrap_horizontal }}
|
||||||
|
{{ form.comment|bootstrap_horizontal }}
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
<button class="btn btn-white" type="reset">{% trans 'Reset' %}</button>
|
||||||
|
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'users:user-update' pk=user.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'users:user-update' pk=user.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="pull-right">
|
||||||
|
<a class="btn btn-outline btn-danger btn-delete-user">
|
||||||
|
<i class="fa fa-edit"></i>Delete
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -395,6 +400,13 @@ $(document).ready(function() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
||||||
});
|
}).on('click', '.btn-delete-user', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = "{{ user.name }}";
|
||||||
|
var uid = "{{ user.id }}";
|
||||||
|
var the_url = '{% url "api-users:user-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||||
|
var redirect_url = "{% url 'users:user-list' %}";
|
||||||
|
objectDelete($this, name, the_url, redirect_url);
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
<h5>{{ action }}</h5>
|
<h5>{{ action }}</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<div class="ibox-content">
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<form method="post" class="form-horizontal" action="" >
|
<form method="post" class="form-horizontal" action="" >
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.name|bootstrap_horizontal }}
|
{{ form.name|bootstrap_horizontal }}
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
<li class="pull-right">
|
<li class="pull-right">
|
||||||
<a class="btn btn-outline btn-default" href="{% url 'users:user-group-update' pk=user_group.id %}"><i class="fa fa-edit"></i>Update</a>
|
<a class="btn btn-outline btn-default" href="{% url 'users:user-group-update' pk=user_group.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="pull-right">
|
||||||
|
<a class="btn btn-outline btn-danger btn-delete-user-group">
|
||||||
|
<i class="fa fa-edit"></i>Delete
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
|
@ -184,6 +189,13 @@ $(document).ready(function () {
|
||||||
});
|
});
|
||||||
console.log(users);
|
console.log(users);
|
||||||
updateGroupMember(users)
|
updateGroupMember(users)
|
||||||
|
}).on('click', '.btn-delete-user-group', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var name = "{{ user_group.name }}";
|
||||||
|
var uid = "{{ user_group.id }}";
|
||||||
|
var the_url = '{% url "api-users:user-group-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||||
|
var redirect_url = "{% url 'users:user-group-list' %}";
|
||||||
|
objectDelete($this, name, the_url, redirect_url);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -33,7 +33,7 @@ class AdminUserRequiredMixin(UserPassesTestMixin):
|
||||||
login_url = reverse_lazy('users:login')
|
login_url = reverse_lazy('users:login')
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
return self.request.user.is_staff
|
return self.request.user.is_superuser
|
||||||
|
|
||||||
|
|
||||||
def user_add_success_next(user):
|
def user_add_success_next(user):
|
||||||
|
@ -122,61 +122,6 @@ def send_reset_ssh_key_mail(user):
|
||||||
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()])
|
|
||||||
#
|
|
||||||
|
|
||||||
def check_user_valid(**kwargs):
|
def check_user_valid(**kwargs):
|
||||||
password = kwargs.pop('password', None)
|
password = kwargs.pop('password', None)
|
||||||
public_key = kwargs.pop('public_key', None)
|
public_key = kwargs.pop('public_key', None)
|
||||||
|
|
|
@ -118,13 +118,14 @@ class UserDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
|
|
||||||
@method_decorator(csrf_exempt, name='dispatch')
|
@method_decorator(csrf_exempt, name='dispatch')
|
||||||
class UserExportView(View):
|
class UserExportView(View):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request):
|
||||||
spm = request.GET.get('spm', '')
|
spm = request.GET.get('spm', '')
|
||||||
users_id = cache.get(spm)
|
users_id = cache.get(spm)
|
||||||
if not users_id and not isinstance(users_id, list):
|
if not users_id and not isinstance(users_id, list):
|
||||||
return HttpResponse('May be expired', status=404)
|
return HttpResponse('May be expired', status=404)
|
||||||
|
|
||||||
users = User.objects.filter(id__in=users_id)
|
users = User.objects.filter(id__in=users_id)
|
||||||
|
print(users)
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
ws = wb.active
|
ws = wb.active
|
||||||
ws.title = 'User'
|
ws.title = 'User'
|
||||||
|
@ -133,9 +134,12 @@ class UserExportView(View):
|
||||||
ws.append(header)
|
ws.append(header)
|
||||||
|
|
||||||
for user in users:
|
for user in users:
|
||||||
ws.append([user.name, user.username, user.email,
|
print(user.name)
|
||||||
','.join([group.name for group in user.groups.all()]),
|
ws.append([
|
||||||
user.role, user.phone, user.wechat, user.comment])
|
user.name, user.username, user.email,
|
||||||
|
','.join([group.name for group in user.groups.all()]),
|
||||||
|
user.role, user.phone, user.wechat, user.comment,
|
||||||
|
])
|
||||||
|
|
||||||
filename = 'users-{}.xlsx'.format(
|
filename = 'users-{}.xlsx'.format(
|
||||||
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
|
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
|
||||||
|
@ -144,7 +148,7 @@ class UserExportView(View):
|
||||||
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request):
|
||||||
try:
|
try:
|
||||||
users_id = json.loads(request.body).get('users_id', [])
|
users_id = json.loads(request.body).get('users_id', [])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -180,11 +184,13 @@ class UserBulkImportView(AdminUserRequiredMixin, JSONResponseMixin, FormView):
|
||||||
return self.render_json_response(data)
|
return self.render_json_response(data)
|
||||||
|
|
||||||
rows = ws.rows
|
rows = ws.rows
|
||||||
header_need = ["name", 'username', 'email', 'groups', "role", "phone", "wechat", "comment"]
|
header_need = ["name", 'username', 'email', 'groups',
|
||||||
|
"role", "phone", "wechat", "comment"]
|
||||||
header = [col.value for col in next(rows)]
|
header = [col.value for col in next(rows)]
|
||||||
print(header)
|
print(header)
|
||||||
if header != header_need:
|
if header != header_need:
|
||||||
data = {'valid': False, 'msg': 'Must be same format as template or export file'}
|
data = {'valid': False, 'msg': 'Must be same format as '
|
||||||
|
'template or export file'}
|
||||||
return self.render_json_response(data)
|
return self.render_json_response(data)
|
||||||
|
|
||||||
created = []
|
created = []
|
||||||
|
|
|
@ -18,8 +18,8 @@ class Config:
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = os.environ.get('SECRET_KEY') or '2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=%s_qj$1%x'
|
SECRET_KEY = os.environ.get('SECRET_KEY') or '2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=%s_qj$1%x'
|
||||||
|
|
||||||
# How many line display every page, default 20
|
# How many line display every page, default 25
|
||||||
DISPLAY_PER_PAGE = 20
|
DISPLAY_PER_PAGE = 25
|
||||||
|
|
||||||
# It's used to identify your site, When we send a create mail to user, we only know login url is /login/
|
# It's used to identify your site, When we send a create mail to user, we only know login url is /login/
|
||||||
# But we should know the absolute url like: http://jms.jumpserver.org/login/, so SITE_URL is
|
# But we should know the absolute url like: http://jms.jumpserver.org/login/, so SITE_URL is
|
||||||
|
|
Loading…
Reference in New Issue