mirror of https://github.com/jumpserver/jumpserver
[Fixture] 添加用户信息更改
parent
0983f294b7
commit
3fa5ce5404
|
@ -3,7 +3,7 @@
|
|||
<li class="nav-header">
|
||||
<div class="dropdown profile-element">
|
||||
<span>
|
||||
<img alt="image" class="img-circle" width="48" height="48" src="{% static "img/root.png" %}"/>
|
||||
<img alt="image" class="img-circle" width="48" height="48" src="{{ user.avatar_url }}"/>
|
||||
</span>
|
||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
|
||||
<span class="clear">
|
||||
|
|
|
@ -41,8 +41,8 @@ class UserProfileForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
'username', 'name', 'email', 'groups', 'wechat',
|
||||
'phone',
|
||||
'username', 'name', 'email',
|
||||
'wechat', 'phone',
|
||||
]
|
||||
help_texts = {
|
||||
'username': '* required',
|
||||
|
@ -51,6 +51,66 @@ class UserProfileForm(forms.ModelForm):
|
|||
}
|
||||
|
||||
|
||||
class UserPasswordForm(forms.Form):
|
||||
old_password = forms.CharField(
|
||||
min_length=5, max_length=128, widget=forms.PasswordInput)
|
||||
new_password = forms.CharField(
|
||||
min_length=5, max_length=128, widget=forms.PasswordInput)
|
||||
confirm_password = forms.CharField(
|
||||
min_length=5, max_length=128, widget=forms.PasswordInput)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.instance = kwargs.pop('instance')
|
||||
super(UserPasswordForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean_old_password(self):
|
||||
old_password = self.cleaned_data['old_password']
|
||||
if not self.instance.check_password(old_password):
|
||||
raise forms.ValidationError(_('Old password error'))
|
||||
return old_password
|
||||
|
||||
def clean_confirm_password(self):
|
||||
new_password = self.cleaned_data['new_password']
|
||||
confirm_password = self.cleaned_data['confirm_password']
|
||||
|
||||
if new_password != confirm_password:
|
||||
raise forms.ValidationError(_('Password does not match'))
|
||||
return confirm_password
|
||||
|
||||
def save(self):
|
||||
password = self.cleaned_data['new_password']
|
||||
self.instance.set_password(password)
|
||||
self.instance.save()
|
||||
return self.instance
|
||||
|
||||
|
||||
class UserPublicKeyForm(forms.Form):
|
||||
public_key = forms.CharField(
|
||||
label=_('ssh public key'), max_length=5000,
|
||||
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
|
||||
help_text=_('Paste your id_rsa.pub here.'))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.instance = kwargs.pop('instance')
|
||||
super(UserPublicKeyForm, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean_public_key(self):
|
||||
public_key = self.cleaned_data['public_key']
|
||||
if self.instance.public_key and public_key == self.instance.public_key:
|
||||
raise forms.ValidationError(_('Public key should not be the '
|
||||
'same as your old one.'))
|
||||
|
||||
if not validate_ssh_public_key(public_key):
|
||||
raise forms.ValidationError(_('Not a valid ssh public key'))
|
||||
return public_key
|
||||
|
||||
def save(self):
|
||||
public_key = self.cleaned_data['public_key']
|
||||
self.instance.public_key = public_key
|
||||
self.instance.save()
|
||||
return self.instance
|
||||
|
||||
|
||||
class UserBulkImportForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = User
|
||||
|
@ -76,25 +136,10 @@ class UserInfoForm(forms.Form):
|
|||
enable_otp = forms.BooleanField(required=False, label=_('enable otp'))
|
||||
|
||||
|
||||
class UserKeyForm(forms.Form):
|
||||
public_key = forms.CharField(
|
||||
label=_('ssh public key'), max_length=5000,
|
||||
widget=forms.Textarea(attrs={'placeholder': _('ssh-rsa AAAA...')}),
|
||||
help_text=_('Paste your id_rsa.pub here.'))
|
||||
|
||||
def clean_public_key(self):
|
||||
public_key = self.cleaned_data['public_key']
|
||||
if self.user.public_key and public_key == self.user.public_key:
|
||||
raise forms.ValidationError(_('Public key should not be the '
|
||||
'same as your old one.'))
|
||||
|
||||
if not validate_ssh_public_key(public_key):
|
||||
raise forms.ValidationError(_('Not a valid ssh public key'))
|
||||
return public_key
|
||||
|
||||
|
||||
class UserPrivateAssetPermissionForm(forms.ModelForm):
|
||||
|
||||
def save(self, commit=True):
|
||||
self.instance = super(UserPrivateAssetPermissionForm, self)\
|
||||
.save(commit=commit)
|
||||
|
@ -121,7 +166,6 @@ class UserPrivateAssetPermissionForm(forms.ModelForm):
|
|||
|
||||
|
||||
class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
|
||||
|
||||
def save(self, commit=True):
|
||||
self.instance = super(UserGroupPrivateAssetPermissionForm, self)\
|
||||
.save(commit=commit)
|
||||
|
|
|
@ -101,14 +101,17 @@ class User(AbstractUser):
|
|||
self._public_key = signer.sign(public_key_raw)
|
||||
|
||||
@property
|
||||
def public_key_hash(self):
|
||||
def public_key_obj(self):
|
||||
class PubKey(object):
|
||||
def __getattr__(self, item):
|
||||
return ''
|
||||
if self.public_key:
|
||||
import sshpubkeys
|
||||
try:
|
||||
return sshpubkeys.SSHKey(self.public_key).hash_md5()
|
||||
return sshpubkeys.SSHKey(self.public_key)
|
||||
except TabError:
|
||||
pass
|
||||
return 'None'
|
||||
return PubKey()
|
||||
|
||||
@property
|
||||
def is_superuser(self):
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/cropper/cropper.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
|
||||
<style>
|
||||
.crop {
|
||||
width: 200px;
|
||||
height: 150px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.img-preview-sm img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: -75px 0 0 -100px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%; /* This rule is very important, please do not ignore this! */
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li>
|
||||
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content" style="background-color: #ffffff">
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.old_password|bootstrap_horizontal}}
|
||||
{{ form.new_password|bootstrap_horizontal }}
|
||||
{{ form.confirm_password|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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/cropper/cropper.min.js' %}"></script>
|
||||
<script>
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -68,8 +68,21 @@
|
|||
<td>{{ user.enable_otp|yesno:"Yes,No,Unkown" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">{% trans 'Public key fingerprint' %}</td>
|
||||
<td>{{ user.public_key_hash }}</td>
|
||||
<td class="text-navy">{% trans 'Public key' %}</td>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
{{ user.public_key_obj.comment }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
{{ user.public_key_obj.hash_md5 }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">{% trans 'Date joined' %}</td>
|
||||
|
@ -123,7 +136,7 @@
|
|||
<td>{% trans 'Reset password' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-password-update' %}">{% trans 'Reset' %}</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -131,27 +144,10 @@
|
|||
<td>{% trans 'Reset public key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" style="width: 54px">{% trans 'Reset' %}</button>
|
||||
<a type="button" class="btn btn-primary btn-xs" style="width: 54px" href="{% url 'users:user-pubkey-update' %}">{% trans 'Reset' %}</a>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Test admin user' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Test' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Test system pingpong' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_reset_pk" style="width: 54px;">{% trans 'Test' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
height: 64px;
|
||||
margin: -75px 0 0 -100px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%; /* This rule is very important, please do not ignore this! */
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
|
@ -30,13 +34,13 @@
|
|||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="" class="text-center">{% trans 'Profile' %} </a>
|
||||
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="text-center">{% trans 'Password' %} </a>
|
||||
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="text-center">{% trans 'Public key' %} </a>
|
||||
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -45,7 +49,6 @@
|
|||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Account' %}</h3>
|
||||
{# {{ form.avatar|bootstrap_horizontal }}#}
|
||||
{{ form.username|bootstrap_horizontal }}
|
||||
{{ form.name|bootstrap_horizontal }}
|
||||
{{ form.email|bootstrap_horizontal }}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/cropper/cropper.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
|
||||
<style>
|
||||
.crop {
|
||||
width: 200px;
|
||||
height: 150px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.img-preview-sm img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: -75px 0 0 -100px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%; /* This rule is very important, please do not ignore this! */
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li>
|
||||
<a href="{% url 'users:user-profile-update' %}" class="text-center">{% trans 'Profile' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'users:user-password-update' %}" class="text-center">{% trans 'Password' %} </a>
|
||||
</li>
|
||||
<li class="active">
|
||||
<a href="{% url 'users:user-pubkey-update' %}" class="text-center">{% trans 'Public key' %} </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content" style="background-color: #ffffff">
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<h3>{% trans 'Old public key' %}</h3>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2 col-lg-2" style="padding-top: 0" >{% trans 'Name' %}</label>
|
||||
<div class=" col-sm-9 col-lg-9">
|
||||
<label>{{ user.public_key_obj.comment }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2 col-lg-2" style="padding-top: 0">{% trans 'Fingerprint' %}</label>
|
||||
<div class=" col-sm-9 col-lg-9 ">
|
||||
<label>{{ user.public_key_obj.hash_md5 }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<h3>{% trans 'Update public key' %}</h3>
|
||||
{{ form.public_key|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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block custom_foot_js %}
|
||||
<script src="{% static 'js/plugins/cropper/cropper.min.js' %}"></script>
|
||||
<script>
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -28,6 +28,12 @@ urlpatterns = [
|
|||
url(r'^profile/update/$',
|
||||
views.UserProfileUpdateView.as_view(),
|
||||
name='user-profile-update'),
|
||||
url(r'^profile/password/update/$',
|
||||
views.UserPasswordUpdateView.as_view(),
|
||||
name='user-password-update'),
|
||||
url(r'^profile/pubkey/update/$',
|
||||
views.UserPublicKeyUpdateView.as_view(),
|
||||
name='user-pubkey-update'),
|
||||
|
||||
# User view
|
||||
url(r'^user$', views.UserListView.as_view(), name='user-list'),
|
||||
|
|
|
@ -154,7 +154,7 @@ class UserResetPasswordView(TemplateView):
|
|||
|
||||
class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
|
||||
template_name = 'users/first_login.html'
|
||||
form_list = [forms.UserInfoForm, forms.UserKeyForm]
|
||||
form_list = [forms.UserInfoForm, forms.UserPublicKeyForm]
|
||||
file_storage = default_storage
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
|
|
|
@ -25,6 +25,7 @@ from django.views.generic.edit import (CreateView, UpdateView, FormMixin,
|
|||
FormView)
|
||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.contrib.auth import logout as auth_logout
|
||||
|
||||
from .. import forms
|
||||
from ..models import User, UserGroup
|
||||
|
@ -37,7 +38,8 @@ __all__ = ['UserListView', 'UserCreateView', 'UserDetailView',
|
|||
'UserUpdateView', 'UserAssetPermissionCreateView',
|
||||
'UserAssetPermissionView', 'UserGrantedAssetView',
|
||||
'UserExportView', 'UserBulkImportView', 'UserProfileView',
|
||||
'UserProfileUpdateView',
|
||||
'UserProfileUpdateView', 'UserPasswordUpdateView',
|
||||
'UserPublicKeyUpdateView',
|
||||
]
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
@ -341,12 +343,49 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView):
|
|||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
from perms.utils import get_user_granted_assets
|
||||
assets = get_user_granted_assets(self.request.user)
|
||||
context = {
|
||||
'app': 'User',
|
||||
'action': 'User Profile',
|
||||
'assets': assets,
|
||||
'action': 'Profile update',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(UserProfileUpdateView, self).get_context_data(**kwargs)
|
||||
return super(UserProfileUpdateView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class UserPasswordUpdateView(LoginRequiredMixin, UpdateView):
|
||||
template_name = 'users/user_password_update.html'
|
||||
model = User
|
||||
form_class = forms.UserPasswordForm
|
||||
success_url = reverse_lazy('users:user-profile')
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.request.user
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'User',
|
||||
'action': 'Password update',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(UserPasswordUpdateView, self).get_context_data(**kwargs)
|
||||
|
||||
def get_success_url(self):
|
||||
auth_logout(self.request)
|
||||
return super(UserPasswordUpdateView, self).get_success_url()
|
||||
|
||||
|
||||
class UserPublicKeyUpdateView(LoginRequiredMixin, UpdateView):
|
||||
template_name = 'users/user_pubkey_update.html'
|
||||
model = User
|
||||
form_class = forms.UserPublicKeyForm
|
||||
success_url = reverse_lazy('users:user-profile')
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.request.user
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
'app': 'User',
|
||||
'action': 'Public key update',
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(UserPublicKeyUpdateView, self).get_context_data(**kwargs)
|
||||
|
|
Loading…
Reference in New Issue