Commit 3fa5ce54 authored by ibuler's avatar ibuler

[Fixture] 添加用户信息更改

parent 0983f294
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<li class="nav-header"> <li class="nav-header">
<div class="dropdown profile-element"> <div class="dropdown profile-element">
<span> <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> </span>
<a data-toggle="dropdown" class="dropdown-toggle" href="#"> <a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="clear"> <span class="clear">
......
...@@ -41,8 +41,8 @@ class UserProfileForm(forms.ModelForm): ...@@ -41,8 +41,8 @@ class UserProfileForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
fields = [ fields = [
'username', 'name', 'email', 'groups', 'wechat', 'username', 'name', 'email',
'phone', 'wechat', 'phone',
] ]
help_texts = { help_texts = {
'username': '* required', 'username': '* required',
...@@ -51,6 +51,66 @@ class UserProfileForm(forms.ModelForm): ...@@ -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 UserBulkImportForm(forms.ModelForm):
class Meta: class Meta:
model = User model = User
...@@ -76,25 +136,10 @@ class UserInfoForm(forms.Form): ...@@ -76,25 +136,10 @@ class UserInfoForm(forms.Form):
enable_otp = forms.BooleanField(required=False, label=_('enable otp')) 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): class UserPrivateAssetPermissionForm(forms.ModelForm):
def save(self, commit=True): def save(self, commit=True):
self.instance = super(UserPrivateAssetPermissionForm, self)\ self.instance = super(UserPrivateAssetPermissionForm, self)\
.save(commit=commit) .save(commit=commit)
...@@ -121,7 +166,6 @@ class UserPrivateAssetPermissionForm(forms.ModelForm): ...@@ -121,7 +166,6 @@ class UserPrivateAssetPermissionForm(forms.ModelForm):
class UserGroupPrivateAssetPermissionForm(forms.ModelForm): class UserGroupPrivateAssetPermissionForm(forms.ModelForm):
def save(self, commit=True): def save(self, commit=True):
self.instance = super(UserGroupPrivateAssetPermissionForm, self)\ self.instance = super(UserGroupPrivateAssetPermissionForm, self)\
.save(commit=commit) .save(commit=commit)
......
...@@ -101,14 +101,17 @@ class User(AbstractUser): ...@@ -101,14 +101,17 @@ class User(AbstractUser):
self._public_key = signer.sign(public_key_raw) self._public_key = signer.sign(public_key_raw)
@property @property
def public_key_hash(self): def public_key_obj(self):
class PubKey(object):
def __getattr__(self, item):
return ''
if self.public_key: if self.public_key:
import sshpubkeys import sshpubkeys
try: try:
return sshpubkeys.SSHKey(self.public_key).hash_md5() return sshpubkeys.SSHKey(self.public_key)
except TabError: except TabError:
pass pass
return 'None' return PubKey()
@property @property
def is_superuser(self): def is_superuser(self):
......
{% 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 @@ ...@@ -68,8 +68,21 @@
<td>{{ user.enable_otp|yesno:"Yes,No,Unkown" }}</td> <td>{{ user.enable_otp|yesno:"Yes,No,Unkown" }}</td>
</tr> </tr>
<tr> <tr>
<td class="text-navy">{% trans 'Public key fingerprint' %}</td> <td class="text-navy">{% trans 'Public key' %}</td>
<td>{{ user.public_key_hash }}</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>
<tr> <tr>
<td class="text-navy">{% trans 'Date joined' %}</td> <td class="text-navy">{% trans 'Date joined' %}</td>
...@@ -123,7 +136,7 @@ ...@@ -123,7 +136,7 @@
<td>{% trans 'Reset password' %}:</td> <td>{% trans 'Reset password' %}:</td>
<td> <td>
<span class="pull-right"> <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> </span>
</td> </td>
</tr> </tr>
...@@ -131,27 +144,10 @@ ...@@ -131,27 +144,10 @@
<td>{% trans 'Reset public key' %}:</td> <td>{% trans 'Reset public key' %}:</td>
<td> <td>
<span class="pull-right"> <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> </span>
</td> </td>
</tr> </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> </tbody>
</table> </table>
</div> </div>
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
height: 64px; height: 64px;
margin: -75px 0 0 -100px; margin: -75px 0 0 -100px;
} }
img {
max-width: 100%; /* This rule is very important, please do not ignore this! */
}
</style> </style>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
...@@ -30,13 +34,13 @@ ...@@ -30,13 +34,13 @@
<div class="panel-options"> <div class="panel-options">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <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>
<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>
<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> </li>
</ul> </ul>
</div> </div>
...@@ -45,7 +49,6 @@ ...@@ -45,7 +49,6 @@
<form method="post" class="form-horizontal" action="" enctype="multipart/form-data"> <form method="post" class="form-horizontal" action="" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
<h3>{% trans 'Account' %}</h3> <h3>{% trans 'Account' %}</h3>
{# {{ form.avatar|bootstrap_horizontal }}#}
{{ form.username|bootstrap_horizontal }} {{ form.username|bootstrap_horizontal }}
{{ form.name|bootstrap_horizontal }} {{ form.name|bootstrap_horizontal }}
{{ form.email|bootstrap_horizontal }} {{ form.email|bootstrap_horizontal }}
......
{% 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 = [ ...@@ -28,6 +28,12 @@ urlpatterns = [
url(r'^profile/update/$', url(r'^profile/update/$',
views.UserProfileUpdateView.as_view(), views.UserProfileUpdateView.as_view(),
name='user-profile-update'), 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 # User view
url(r'^user$', views.UserListView.as_view(), name='user-list'), url(r'^user$', views.UserListView.as_view(), name='user-list'),
......
...@@ -154,7 +154,7 @@ class UserResetPasswordView(TemplateView): ...@@ -154,7 +154,7 @@ class UserResetPasswordView(TemplateView):
class UserFirstLoginView(LoginRequiredMixin, SessionWizardView): class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
template_name = 'users/first_login.html' template_name = 'users/first_login.html'
form_list = [forms.UserInfoForm, forms.UserKeyForm] form_list = [forms.UserInfoForm, forms.UserPublicKeyForm]
file_storage = default_storage file_storage = default_storage
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
......
...@@ -25,6 +25,7 @@ from django.views.generic.edit import (CreateView, UpdateView, FormMixin, ...@@ -25,6 +25,7 @@ from django.views.generic.edit import (CreateView, UpdateView, FormMixin,
FormView) FormView)
from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.generic.detail import DetailView, SingleObjectMixin
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import logout as auth_logout
from .. import forms from .. import forms
from ..models import User, UserGroup from ..models import User, UserGroup
...@@ -37,7 +38,8 @@ __all__ = ['UserListView', 'UserCreateView', 'UserDetailView', ...@@ -37,7 +38,8 @@ __all__ = ['UserListView', 'UserCreateView', 'UserDetailView',
'UserUpdateView', 'UserAssetPermissionCreateView', 'UserUpdateView', 'UserAssetPermissionCreateView',
'UserAssetPermissionView', 'UserGrantedAssetView', 'UserAssetPermissionView', 'UserGrantedAssetView',
'UserExportView', 'UserBulkImportView', 'UserProfileView', 'UserExportView', 'UserBulkImportView', 'UserProfileView',
'UserProfileUpdateView', 'UserProfileUpdateView', 'UserPasswordUpdateView',
'UserPublicKeyUpdateView',
] ]
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -341,12 +343,49 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView): ...@@ -341,12 +343,49 @@ class UserProfileUpdateView(LoginRequiredMixin, UpdateView):
) )
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
from perms.utils import get_user_granted_assets
assets = get_user_granted_assets(self.request.user)
context = { context = {
'app': 'User', 'app': 'User',
'action': 'User Profile', 'action': 'Profile update',
'assets': assets,
} }
kwargs.update(context) 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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment