mirror of
https://gitlab.science.ru.nl/technicie/MarietjeDjango.git
synced 2025-12-11 09:42:20 +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',
|
(_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
|
||||||
'groups', 'user_permissions')}),
|
'groups', 'user_permissions')}),
|
||||||
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
|
||||||
|
(_('Activation'), {'fields': ('activation_token', 'reset_token')}),
|
||||||
)
|
)
|
||||||
list_display = ('username', 'email', 'name', 'is_staff')
|
list_display = ('username', 'email', 'name', 'is_staff')
|
||||||
search_fields = ('username', 'name', 'email')
|
search_fields = ('username', 'name', 'email')
|
||||||
|
|||||||
@ -9,7 +9,7 @@ class AuthenticationForm(BaseAuthenticationForm):
|
|||||||
super(AuthenticationForm, self).__init__(request, *args, **kwargs)
|
super(AuthenticationForm, self).__init__(request, *args, **kwargs)
|
||||||
|
|
||||||
def confirm_login_allowed(self, user):
|
def confirm_login_allowed(self, user):
|
||||||
if user.activation_token is not None:
|
if user.activation_token:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
self.error_messages['inactive'],
|
self.error_messages['inactive'],
|
||||||
code='inactive',
|
code='inactive',
|
||||||
@ -68,7 +68,39 @@ class RegistrationForm(forms.ModelForm):
|
|||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
user = super(RegistrationForm, self).save(commit=False)
|
user = super(RegistrationForm, self).save(commit=False)
|
||||||
user.set_password(self.cleaned_data["password1"])
|
user.set_password(self.cleaned_data.get("password1"))
|
||||||
if commit:
|
if commit:
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
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
|
null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
reset_token = models.TextField(
|
||||||
|
_('reset token'),
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
USERNAME_FIELD = 'username'
|
USERNAME_FIELD = 'username'
|
||||||
REQUIRED_FIELDS = ['email', 'name']
|
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>
|
</div>
|
||||||
<div class="text-center">
|
<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>
|
</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 django.contrib import admin
|
||||||
from queues.views import index
|
from queues.views import index
|
||||||
from django.contrib.auth.views import login, logout
|
from django.contrib.auth.views import login, logout
|
||||||
from .views import register, activate
|
from .views import register, activate, forgotpassword, resetpassword
|
||||||
from .forms import AuthenticationForm
|
from .forms import AuthenticationForm
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', index, name='index'),
|
url(r'^$', index, name='index'),
|
||||||
url(r'^login/$', login, {'authentication_form': AuthenticationForm}, name='login'),
|
url(r'^login/$', login, {'authentication_form': AuthenticationForm}, name='login'),
|
||||||
url(r'^logout/$', logout, name='logout'),
|
url(r'^logout/$', logout, name='logout'),
|
||||||
url(r'^register/$', register, name='register'),
|
url(r'^register/$', register, name='register'),
|
||||||
url(r'^activate/(\d+)/(\w+)/$', activate, name='activate'),
|
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'^admin/', admin.site.urls),
|
||||||
url(r'^songs/', include('songs.urls')),
|
url(r'^songs/', include('songs.urls')),
|
||||||
url(r'^api/', include('api.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.core.mail import send_mail
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from .forms import RegistrationForm
|
from .forms import RegistrationForm, ResetPasswordForm
|
||||||
from marietje.utils import get_first_queue
|
from marietje.utils import get_first_queue
|
||||||
|
|
||||||
|
|
||||||
@ -31,9 +31,8 @@ def register(request):
|
|||||||
'Please confirm your account by following this link: ' + activation_link,
|
'Please confirm your account by following this link: ' + activation_link,
|
||||||
settings.MAIL_FROM,
|
settings.MAIL_FROM,
|
||||||
[user.email],
|
[user.email],
|
||||||
fail_silently=False,
|
fail_silently=True
|
||||||
)
|
)
|
||||||
|
|
||||||
return redirect('login')
|
return redirect('login')
|
||||||
|
|
||||||
|
|
||||||
@ -44,3 +43,45 @@ def activate(request, user_id, token):
|
|||||||
user.activation_token = None
|
user.activation_token = None
|
||||||
user.save()
|
user.save()
|
||||||
return redirect('login')
|
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