Reset password functionality.

This commit is contained in:
Jim Driessen
2017-01-30 03:37:08 +01:00
parent c18f733448
commit c972671186
9 changed files with 167 additions and 8 deletions

View File

@ -12,6 +12,7 @@ class UserAdmin(BaseUserAdmin):
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
'groups', 'user_permissions')}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
(_('Activation'), {'fields': ('activation_token', 'reset_token')}),
)
list_display = ('username', 'email', 'name', 'is_staff')
search_fields = ('username', 'name', 'email')

View File

@ -9,7 +9,7 @@ class AuthenticationForm(BaseAuthenticationForm):
super(AuthenticationForm, self).__init__(request, *args, **kwargs)
def confirm_login_allowed(self, user):
if user.activation_token is not None:
if user.activation_token:
raise forms.ValidationError(
self.error_messages['inactive'],
code='inactive',
@ -68,7 +68,39 @@ class RegistrationForm(forms.ModelForm):
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
user.set_password(self.cleaned_data.get("password1"))
if commit:
user.save()
return user
class ResetPasswordForm(forms.Form):
error_messages = {
'password_mismatch': _("The two password fields didn't match."),
}
password1 = forms.CharField(
label=_("Password"),
strip=False,
widget=forms.PasswordInput,
)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput,
strip=False,
help_text=_("Enter the same password as before, for verification."),
)
def __init__(self, *args, **kwargs):
super(ResetPasswordForm, self).__init__(*args, **kwargs)
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
password_validation.validate_password(self.cleaned_data.get('password2'))
return password2

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-01-29 18:55
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('marietje', '0003_auto_20170117_2320'),
]
operations = [
migrations.AddField(
model_name='user',
name='reset_token',
field=models.TextField(blank=True, null=True, verbose_name='reset token'),
),
]

View File

@ -94,6 +94,12 @@ class User(AbstractBaseUser, PermissionsMixin):
null=True
)
reset_token = models.TextField(
_('reset token'),
blank=True,
null=True
)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'name']

View File

@ -0,0 +1,27 @@
{% extends 'base.html' %}
{% block title %}Reset Password{% endblock %}
{% block content %}
<form method="POST" action="{% url 'forgotpassword' %}">
{% csrf_token %}
<div class="row centered-form">
<div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Reset Password</h3>
</div>
<div class="panel-body">
<div class="form-group">
<div class="input-group">
<input name="email" type="text" class="form-control" placeholder="Email address" aria-describedby="email-postfix">
<span class="input-group-addon" id="email-postfix">@science.ru.nl</span>
</div>
</div>
<input type="submit" value="Reset Password" class="btn btn-primary btn-block">
</div>
</div>
</div>
</div>
</form>
{% endblock %}

View File

@ -27,7 +27,8 @@
</div>
</div>
<div class="text-center">
<a href="/register" >Don't have an account? Register</a>
<a href="{% url 'register' %}" >Don't have an account? Register</a><br>
<a href="{% url 'forgotpassword' %}" >Forgot your password? Reset password</a>
</div>
</div>
</div>

View File

@ -0,0 +1,30 @@
{% extends 'base.html' %}
{% block title %}Reset Password{% endblock %}
{% block content %}
<form method="POST" action="{% url 'resetpassword' user_id reset_token %}">
{% csrf_token %}
<input type="hidden" name="user_id" />
<input type="hidden" name="reset_token" />
<div class="row centered-form">
<div class="col-xs-12 col-sm-8 col-md-4 col-sm-offset-2 col-md-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Reset Password</h3>
</div>
<div class="panel-body">
<div class="form-group">
<input type="password" name="password1" class="form-control input-sm" placeholder="Password">
</div>
<div class="form-group">
<input type="password" name="password2" class="form-control input-sm" placeholder="Confirm Password">
</div>
<input type="submit" value="Reset Password" class="btn btn-primary btn-block">
</div>
</div>
</div>
</div>
</form>
{% endblock %}

View File

@ -17,17 +17,18 @@ from django.conf.urls import include, url
from django.contrib import admin
from queues.views import index
from django.contrib.auth.views import login, logout
from .views import register, activate
from .views import register, activate, forgotpassword, resetpassword
from .forms import AuthenticationForm
urlpatterns = [
url(r'^$', index, name='index'),
url(r'^login/$', login, {'authentication_form': AuthenticationForm}, name='login'),
url(r'^logout/$', logout, name='logout'),
url(r'^register/$', register, name='register'),
url(r'^activate/(\d+)/(\w+)/$', activate, name='activate'),
url(r'^forgotpassword/$', forgotpassword, name='forgotpassword'),
url(r'^resetpassword/(\d+)/(\w+)/$', resetpassword, name='resetpassword'),
url(r'^admin/', admin.site.urls),
url(r'^songs/', include('songs.urls')),
url(r'^api/', include('api.urls')),

View File

@ -4,7 +4,7 @@ from django.contrib.auth import get_user_model
from django.core.mail import send_mail
from django.conf import settings
from django.urls import reverse
from .forms import RegistrationForm
from .forms import RegistrationForm, ResetPasswordForm
from marietje.utils import get_first_queue
@ -31,9 +31,8 @@ def register(request):
'Please confirm your account by following this link: ' + activation_link,
settings.MAIL_FROM,
[user.email],
fail_silently=False,
fail_silently=True
)
return redirect('login')
@ -44,3 +43,45 @@ def activate(request, user_id, token):
user.activation_token = None
user.save()
return redirect('login')
def forgotpassword(request):
if not request.POST:
return render(request, 'registration/forgotpassword.html')
User = get_user_model()
user = User.objects.filter(username=request.POST.get('email')).first()
if user is None or user.activation_token:
return render(request, 'registration/forgotpassword.html')
user.reset_token = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32))
user.save()
reset_link = request.build_absolute_uri(reverse('resetpassword', args=[user.id, user.reset_token]))
send_mail('Marietje - Reset password',
'You have requested to reset your password. You can reset your password by following this link: '
+ reset_link + '\nIf you did not request to reset your password, you can ignore this email.',
settings.MAIL_FROM,
[user.email],
fail_silently=True
)
return redirect('login')
def resetpassword(request, user_id, token):
User = get_user_model()
user = get_object_or_404(User, pk=user_id)
if not user.reset_token or token != user.reset_token:
return redirect('login')
if not request.POST:
return render(request, 'registration/resetpassword.html', {'user_id': user.id, 'reset_token': token})
form = ResetPasswordForm(request.POST)
if not form.is_valid():
return render(request, 'registration/resetpassword.html', {'user_id': user.id, 'reset_token': token, 'form': form})
user.reset_token = None
user.set_password(form.cleaned_data['password1'])
user.save()
return redirect('login')