Allow user to edit their username in the Edit Profile form

Users may want to change their usernames for a number of different
reasons, but at the moment we require them to contact an admin to do
that. Provided we validate the new username correctly and add a CAPTCHA
to make automated enumeration difficult, we can add username to the Edit
Profile form and then users can do that any time they wish.

While we're doing this, show a message when the profile is successfully
updated.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2018-10-18 10:09:06 +13:00
parent 2c8f979f9c
commit 091f5e4ef8
3 changed files with 35 additions and 3 deletions

View File

@ -8,6 +8,7 @@ from collections import OrderedDict
from layerindex.models import LayerItem, LayerBranch, LayerMaintainer, LayerNote, RecipeChangeset, RecipeChange, ClassicRecipe from layerindex.models import LayerItem, LayerBranch, LayerMaintainer, LayerNote, RecipeChangeset, RecipeChange, ClassicRecipe
from django import forms from django import forms
from django.core.validators import URLValidator, RegexValidator, EmailValidator from django.core.validators import URLValidator, RegexValidator, EmailValidator
from registration.validators import ReservedNameValidator, DEFAULT_RESERVED_NAMES, validate_confusables
from django.forms.models import inlineformset_factory, modelformset_factory from django.forms.models import inlineformset_factory, modelformset_factory
from captcha.fields import CaptchaField from captcha.fields import CaptchaField
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -178,9 +179,24 @@ class EditNoteForm(StyledModelForm):
class EditProfileForm(StyledModelForm): class EditProfileForm(StyledModelForm):
captcha = CaptchaField(label='Verification', help_text='Please enter the letters displayed for verification purposes', error_messages={'invalid':'Incorrect entry, please try again'})
class Meta: class Meta:
model = User model = User
fields = ('first_name', 'last_name', 'email') fields = ('username', 'first_name', 'last_name', 'email', 'captcha')
def clean_username(self):
username = self.cleaned_data['username']
if 'username' in self.changed_data:
try:
reserved_validator = ReservedNameValidator(
reserved_names=DEFAULT_RESERVED_NAMES
)
reserved_validator(username)
validate_confusables(username)
except forms.ValidationError as v:
self.add_error('username', v)
return username
class ClassicRecipeForm(StyledModelForm): class ClassicRecipeForm(StyledModelForm):

View File

@ -824,16 +824,32 @@ class HistoryListView(ListView):
return Revision.objects.all().order_by('-date_created') return Revision.objects.all().order_by('-date_created')
class EditProfileFormView(UpdateView): class EditProfileFormView(SuccessMessageMixin, UpdateView):
form_class = EditProfileForm form_class = EditProfileForm
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.user = request.user self.user = request.user
return super(EditProfileFormView, self).dispatch(request, *args, **kwargs) return super(EditProfileFormView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(EditProfileFormView, self).get_context_data(**kwargs)
form = context['form']
# Prepare a list of fields with errors
# We do this so that if there's a problem with the captcha, that's the only error shown
# (since we have a username field, we want to make user enumeration difficult)
if 'captcha' in form.errors:
error_fields = ['captcha']
else:
error_fields = form.errors.keys()
context['error_fields'] = error_fields
return context
def get_object(self, queryset=None): def get_object(self, queryset=None):
return self.user return self.user
def get_success_message(self, cleaned_data):
return "Profile saved successfully"
def get_success_url(self): def get_success_url(self):
return reverse('frontpage') return reverse('frontpage')

View File

@ -26,7 +26,7 @@
{% endfor %} {% endfor %}
{% for field in form.visible_fields %} {% for field in form.visible_fields %}
{% if field.errors %} {% if field.name in error_fields %}
<div class="form-group alert alert-danger"> <div class="form-group alert alert-danger">
{{ field.errors }} {{ field.errors }}
{% else %} {% else %}