mirror of
https://gitlab.science.ru.nl/technicie/MarietjeDjango.git
synced 2025-12-09 18:52:23 +01:00
Reset password functionality.
This commit is contained in:
@ -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')
|
||||
|
||||
@ -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
|
||||
|
||||
20
marietje/marietje/migrations/0004_user_reset_token.py
Normal file
20
marietje/marietje/migrations/0004_user_reset_token.py
Normal 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'),
|
||||
),
|
||||
]
|
||||
@ -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']
|
||||
|
||||
|
||||
27
marietje/marietje/templates/registration/forgotpassword.html
Normal file
27
marietje/marietje/templates/registration/forgotpassword.html
Normal 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 %}
|
||||
@ -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>
|
||||
|
||||
30
marietje/marietje/templates/registration/resetpassword.html
Normal file
30
marietje/marietje/templates/registration/resetpassword.html
Normal 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 %}
|
||||
@ -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')),
|
||||
|
||||
@ -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')
|
||||
|
||||
Reference in New Issue
Block a user