Added the ability for logged-in users to change their login (username) to any of the active email addresses of the account. Fixes ticket #2052.
- Legacy-Id: 12843
This commit is contained in:
parent
44ad914fba
commit
efc77762be
|
@ -173,7 +173,6 @@ from django import forms
|
|||
class ChangePasswordForm(forms.Form):
|
||||
current_password = forms.CharField(widget=forms.PasswordInput)
|
||||
|
||||
|
||||
new_password = forms.CharField(widget=PasswordStrengthInput)
|
||||
new_password_confirmation = forms.CharField(widget=PasswordConfirmationInput)
|
||||
|
||||
|
@ -185,10 +184,29 @@ class ChangePasswordForm(forms.Form):
|
|||
password = self.cleaned_data.get('current_password', None)
|
||||
if not self.user.check_password(password):
|
||||
raise ValidationError('Invalid password')
|
||||
return password
|
||||
|
||||
def clean(self):
|
||||
new_password = self.cleaned_data.get('new_password', None)
|
||||
conf_password = self.cleaned_data.get('new_password_confirmation', None)
|
||||
if not new_password == conf_password:
|
||||
raise ValidationError("The password confirmation is different than the new password")
|
||||
|
||||
|
||||
|
||||
class ChangeUsernameForm(forms.Form):
|
||||
username = forms.ChoiceField(choices=['-','--------'])
|
||||
password = forms.CharField(widget=forms.PasswordInput, help_text="Confirm the change with your password")
|
||||
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
assert isinstance(user, User)
|
||||
super(ChangeUsernameForm, self).__init__(*args, **kwargs)
|
||||
self.user = user
|
||||
emails = user.person.email_set.filter(active=True)
|
||||
choices = [ (email.address, email.address) for email in emails ]
|
||||
self.fields['username'] = forms.ChoiceField(choices=choices)
|
||||
|
||||
def clean_password(self):
|
||||
password = self.cleaned_data['password']
|
||||
if not self.user.check_password(password):
|
||||
raise ValidationError('Invalid password')
|
||||
return password
|
||||
|
|
|
@ -449,3 +449,50 @@ class IetfAuthTests(TestCase):
|
|||
user = User.objects.get(username="someone@example.com")
|
||||
self.assertTrue(user.check_password(u'foobar'))
|
||||
|
||||
def test_change_username(self):
|
||||
|
||||
chun_url = urlreverse(ietf.ietfauth.views.change_username)
|
||||
prof_url = urlreverse(ietf.ietfauth.views.profile)
|
||||
login_url = urlreverse(django.contrib.auth.views.login)
|
||||
redir_url = '%s?next=%s' % (login_url, chun_url)
|
||||
|
||||
# get without logging in
|
||||
r = self.client.get(chun_url)
|
||||
self.assertRedirects(r, redir_url)
|
||||
|
||||
user = User.objects.create(username="someone@example.com", email="someone@example.com")
|
||||
user.set_password("password")
|
||||
user.save()
|
||||
p = Person.objects.create(name="Some One", ascii="Some One", user=user)
|
||||
Email.objects.create(address=user.username, person=p)
|
||||
Email.objects.create(address="othername@example.org", person=p)
|
||||
|
||||
# log in
|
||||
r = self.client.post(redir_url, {"username":user.username, "password":"password"})
|
||||
self.assertRedirects(r, chun_url)
|
||||
|
||||
# wrong username
|
||||
r = self.client.post(chun_url, {"username": "fiddlesticks",
|
||||
"password": "password",
|
||||
})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertFormError(r, 'form', 'username',
|
||||
"Select a valid choice. fiddlesticks is not one of the available choices.")
|
||||
|
||||
# wrong password
|
||||
r = self.client.post(chun_url, {"username": "othername@example.org",
|
||||
"password": "foobar",
|
||||
})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertFormError(r, 'form', 'password', 'Invalid password')
|
||||
|
||||
# correct username change
|
||||
r = self.client.post(chun_url, {"username": "othername@example.org",
|
||||
"password": "password",
|
||||
})
|
||||
self.assertRedirects(r, prof_url)
|
||||
# refresh user object
|
||||
prev = user
|
||||
user = User.objects.get(username="othername@example.org")
|
||||
self.assertEqual(prev, user)
|
||||
self.assertTrue(user.check_password(u'password'))
|
||||
|
|
|
@ -18,5 +18,6 @@ urlpatterns = [
|
|||
url(r'^reset/confirm/(?P<auth>[^/]+)/$', views.confirm_password_reset),
|
||||
url(r'^review/$', views.review_overview),
|
||||
url(r'^testemail/$', views.test_email),
|
||||
url(r'whitelist/add/?$', views.add_account_whitelist),
|
||||
url(r'^username/$', views.change_username),
|
||||
url(r'^whitelist/add/?$', views.add_account_whitelist),
|
||||
]
|
||||
|
|
|
@ -52,8 +52,9 @@ from django.shortcuts import render, redirect, get_object_or_404
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.group.models import Role, Group
|
||||
from ietf.ietfauth.forms import RegistrationForm, PasswordForm, ResetPasswordForm, TestEmailForm, WhitelistForm, ChangePasswordForm
|
||||
from ietf.ietfauth.forms import get_person_form, RoleEmailForm, NewEmailForm
|
||||
from ietf.ietfauth.forms import ( RegistrationForm, PasswordForm, ResetPasswordForm, TestEmailForm,
|
||||
WhitelistForm, ChangePasswordForm, get_person_form, RoleEmailForm,
|
||||
NewEmailForm, ChangeUsernameForm )
|
||||
from ietf.ietfauth.htpasswd import update_htpasswd_file
|
||||
from ietf.ietfauth.utils import role_required
|
||||
from ietf.mailinglists.models import Subscribed, Whitelisted
|
||||
|
@ -521,3 +522,45 @@ def change_password(request):
|
|||
})
|
||||
|
||||
|
||||
@login_required
|
||||
def change_username(request):
|
||||
person = None
|
||||
|
||||
try:
|
||||
person = request.user.person
|
||||
except Person.DoesNotExist:
|
||||
return render(request, 'registration/missing_person.html')
|
||||
|
||||
emails = [ e.address for e in Email.objects.filter(person=person, active=True) ]
|
||||
emailz = [ e.address for e in person.email_set.filter(active=True) ]
|
||||
assert emails == emailz
|
||||
user = request.user
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ChangeUsernameForm(user, request.POST)
|
||||
if form.is_valid():
|
||||
new_username = form.cleaned_data["username"]
|
||||
password = form.cleaned_data["password"]
|
||||
assert new_username in emails
|
||||
|
||||
user.username = new_username.lower()
|
||||
user.save()
|
||||
# password is also stored in htpasswd file
|
||||
update_htpasswd_file(user.username, password)
|
||||
# keep the session
|
||||
update_session_auth_hash(request, user)
|
||||
|
||||
send_mail(request, emails, None, "Datatracker username change notification", "registration/username_change_email.txt", {})
|
||||
|
||||
messages.success(request, "Your username was successfully changed")
|
||||
return HttpResponseRedirect(urlreverse('ietf.ietfauth.views.profile'))
|
||||
|
||||
else:
|
||||
form = ChangeUsernameForm(request.user)
|
||||
|
||||
return render(request, 'registration/change_username.html', {
|
||||
'form': form,
|
||||
'user': user,
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -17,17 +17,19 @@
|
|||
{% if user.is_authenticated %}
|
||||
<li><a rel="nofollow" href="/accounts/logout/" >Sign out</a></li>
|
||||
<li><a rel="nofollow" href="/accounts/profile/">Account info</a></li>
|
||||
<li><a href="{%url "ietf.cookies.views.preferences" %}" rel="nofollow">Preferences</a></li>
|
||||
<li><a rel="nofollow" href="/accounts/password/">Change password</a></li>
|
||||
<li><a rel="nofollow" href="/accounts/username/">Change username</a></li>
|
||||
{% else %}
|
||||
<li><a rel="nofollow" href="/accounts/login/?next={{request.get_full_path|urlencode}}">Sign in</a></li>
|
||||
<li><a rel="nofollow" href="/accounts/reset/">Password reset</a></li>
|
||||
<li><a href="{%url "ietf.cookies.views.preferences" %}" rel="nofollow">Preferences</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if not request.user.is_authenticated %}
|
||||
<li><a href="{% url "ietf.ietfauth.views.create_account" %}">New account</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{%url "ietf.cookies.views.preferences" %}" rel="nofollow">Preferences</a></li>
|
||||
|
||||
{% if user|has_role:"Reviewer" %}
|
||||
<li><a href="{% url "ietf.ietfauth.views.review_overview" %}">My reviews</a></li>
|
||||
|
|
40
ietf/templates/registration/change_username.html
Normal file
40
ietf/templates/registration/change_username.html
Normal file
|
@ -0,0 +1,40 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}Change username{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-2 col-sm-0"></div>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<h1>Change username</h1>
|
||||
|
||||
<div class="help-block">
|
||||
This form lets you change your username (login) from {{ user.username }} to
|
||||
one of your other active email addresses. If you want to change to a new
|
||||
email address, then please first
|
||||
<a href="{% url 'ietf.ietfauth.views.profile' %}">edit your profile</a>
|
||||
to add that email address to the active email addresses for your account.
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
|
||||
{% buttons %}
|
||||
<button type="submit" class="btn btn-primary">Change username</button>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="col-md-2 col-sm-0"></div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
10
ietf/templates/registration/username_change_email.txt
Normal file
10
ietf/templates/registration/username_change_email.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% autoescape off %}
|
||||
Hello,
|
||||
|
||||
{% filter wordwrap:73 %}The username (login name) for your datatracker account was just changed using the username change form. If this was not done by you, please contact the secretariat at ietf-action@ietf.org for assistance.{% endfilter %}
|
||||
|
||||
Best regards,
|
||||
|
||||
The datatracker account manager service
|
||||
(for the IETF Secretariat)
|
||||
{% endautoescape %}
|
Loading…
Reference in a new issue