Password and User settings Form implemented

This commit is contained in:
Dirk Alders 2024-10-27 19:04:17 +01:00
parent b63cfaa741
commit f31771b588
6 changed files with 138 additions and 49 deletions

View File

@ -1,7 +1,9 @@
from django import forms from django import forms
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordChangeForm
from .models import UserProfile from django.utils.translation import gettext as _
from .models import UserProfile, get_userprofile
from users import emails
class UserRegistrationForm(UserCreationForm): class UserRegistrationForm(UserCreationForm):
@ -24,6 +26,72 @@ class UserProfileFormLanguageOnly(forms.ModelForm):
fields = ['language_code'] fields = ['language_code']
class UserPasswordChangeForm(PasswordChangeForm):
email = forms.EmailField()
first_name = forms.CharField(max_length=150)
last_name = forms.CharField(max_length=150)
field_order = ["email", "first_name", "last_name", "old_password", "new_password1", "new_password2"]
def __init__(self, request):
self.request = request
#
data = request.POST or {'email': request.user.email, 'first_name': request.user.first_name, 'last_name': request.user.last_name}
#
super().__init__(request.user, data)
self.fields['old_password'].widget.attrs.update({'autofocus': False})
self.fields['old_password'].required = False
def clean_old_password(self):
"""
Validation of old_password field only, if set.
"""
old_password = self.cleaned_data["old_password"]
if old_password and not self.user.check_password(old_password):
raise forms.ValidationError(
self.error_messages["password_incorrect"],
code="password_incorrect",
)
return old_password
def clean(self):
"""
Validation of new_passwords only if old_password field is set.
"""
clean_data = forms.Form.clean(self)
old_password = clean_data.get('old_password')
#
if old_password:
self.validate_passwords("new_password1", "new_password2")
self.validate_password_for_user(self.user, "new_password2")
return forms.Form.clean(self)
def save(self, commit=True):
changed = False
for key in self.fields:
new = self.data.get(key)
try:
old = getattr(self.user, key)
except AttributeError:
pass # Is a password field
else:
if new != old:
if key == 'email':
emails.send_validation_mail(self.user, self.request)
up = get_userprofile(self.user)
up.mail_pending = new
up.save()
else:
changed = True
setattr(self.user, key, new)
if self.data.get('new_password1'):
changed = True
self.user.set_password(self.data.get('new_password1'))
#
if changed:
self.user.save()
return changed
class UserActivationForm(UserChangeForm): class UserActivationForm(UserChangeForm):
password = None password = None

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-10-27 17:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0003_userprofile_mail_validated'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='mail_pending',
field=models.EmailField(max_length=254, null=True),
),
]

View File

@ -30,6 +30,7 @@ class UserProfile(models.Model):
timezone = models.CharField(max_length=150, default='UTC', choices=[(t, t) for t in pytz.common_timezones]) timezone = models.CharField(max_length=150, default='UTC', choices=[(t, t) for t in pytz.common_timezones])
language_code = models.CharField(max_length=150, default='en', choices=settings.LANGUAGES) language_code = models.CharField(max_length=150, default='en', choices=settings.LANGUAGES)
mail_validated = models.BooleanField(default=False) mail_validated = models.BooleanField(default=False)
mail_pending = models.EmailField(null=True)
def export_key(self): def export_key(self):
return self.user.username return self.user.username

View File

@ -4,7 +4,14 @@
{% block content %} {% block content %}
<form action="" method="post"> <form action="" method="post">
{% csrf_token %} {% csrf_token %}
{% include 'users/profile_formdata.html' %}
{% get_current_language as LANGUAGE_CODE %}
<h1>{% trans "Language and Timezone" %}</h1>
{{ form_userprofile.as_p }}
<h1>{% trans "Userdata and Password" %}</h1>
{{ form_userchange.as_p }}
<input type="submit" value="{% trans "Save" %}" class="button" /> <input type="submit" value="{% trans "Save" %}" class="button" />
</form> </form>

View File

@ -1,6 +0,0 @@
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
<h1>{% trans "Language and Timezone" %}</h1>
{{ form_userprofile.as_p }}
</select>

View File

@ -11,7 +11,7 @@ from django.contrib.auth.models import User
from django.utils.encoding import force_str from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_decode from django.utils.http import urlsafe_base64_decode
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from .forms import UserRegistrationForm, UserProfileForm, UserActivationForm from .forms import UserRegistrationForm, UserProfileForm, UserActivationForm, UserPasswordChangeForm
import logging import logging
from .models import get_userprofile from .models import get_userprofile
from themes import Context from themes import Context
@ -28,37 +28,28 @@ def password_recovery(request):
return redirect(request.GET.get('next') or '/') return redirect(request.GET.get('next') or '/')
def profile_post_actions(request, context):
if request.POST:
form = context.get('form_userprofile')
if form.is_valid():
form.save()
return redirect(request.GET.get('next') or '/')
def profile_pre_actions(request, context, form_to_be_used=UserProfileForm):
profile = get_userprofile(request.user)
if request.POST:
form = form_to_be_used(request.POST, instance=profile)
else:
form = form_to_be_used(instance=profile)
context['form_userprofile'] = form
@login_required @login_required
def profile(request): def profile(request):
context = Context(request) # needs to be executed first because of time mesurement context = Context(request) # needs to be executed first because of time mesurement
profile_pre_actions(request, context) profile = get_userprofile(request.user)
response = profile_post_actions(request, context) if request.POST:
if response is not None: form_userprofile = UserProfileForm(request.POST, instance=profile)
return response form_userchange = UserPasswordChangeForm(request)
if form_userprofile.is_valid() and form_userchange.is_valid():
form_userprofile.save()
form_userchange.save()
return redirect(request.GET.get('next') or '/')
else: else:
context_adaption( form_userprofile = UserProfileForm(instance=profile)
context, form_userchange = UserPasswordChangeForm(request)
request, context_adaption(
_('Profile for %(username)s') % {'username': request.user.username}, context,
) request,
return render(request, 'users/profile.html', context=context) _('Profile for %(username)s') % {'username': request.user.username},
form_userprofile=form_userprofile,
form_userchange=form_userchange,
)
return render(request, 'users/profile.html', context=context)
def register(request): def register(request):
@ -158,20 +149,30 @@ def validate(request, uidb64, token):
myuser = None myuser = None
if myuser is not None and generate_token.check_token(myuser, token): if myuser is not None and generate_token.check_token(myuser, token):
# Store mail validation to user profile up = get_userprofile(myuser)
profile = get_userprofile(myuser) if up.mail_pending:
profile.mail_validated = True # change of email-address
profile.save() myuser.email = up.mail_pending
if not parameter.get(parameter.USERS_ADMIN_ACTIVATION):
# Activate user
myuser.is_active = True
myuser.save() myuser.save()
messages.success(request, _("Your Account has been activated.")) up.mail_pending = None
return redirect('users-login') up.save()
else: messages.success(request, _("Your new email address is now active."))
emails.send_activation_mail(myuser, request)
messages.success(request, _("Your Email has been validated. Wait for the administrator to activate your account"))
return redirect("/") return redirect("/")
else:
# Store mail validation to user profile
profile = get_userprofile(myuser)
profile.mail_validated = True
profile.save()
if not parameter.get(parameter.USERS_ADMIN_ACTIVATION):
# Activate user
myuser.is_active = True
myuser.save()
messages.success(request, _("Your Account has been activated."))
return redirect('users-login')
else:
emails.send_activation_mail(myuser, request)
messages.success(request, _("Your Email has been validated. Wait for the administrator to activate your account"))
return redirect("/")
else: else:
context_adaption( context_adaption(
context, context,