Moves user activation away from just clicking on reset password
To following the link in the password reset email
This commit is contained in:
72
common/djangoapps/student/forms.py
Normal file
72
common/djangoapps/student/forms.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
from django.template import loader
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.hashers import UNUSABLE_PASSWORD, is_password_usable, get_hasher
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.contrib.sites.models import get_current_site
|
||||
from django.utils.http import int_to_base36
|
||||
|
||||
|
||||
|
||||
# This is a literal copy from Django 1.4.5's django.contrib.auth.forms.PasswordResetForm
|
||||
# I think copy-and-paste here is somewhat better than subclassing and
|
||||
# just changing the definition of clean_email, because it's less
|
||||
# likely to be broken by incompatibility with a new django version.
|
||||
# (If this form is good enough now, a snapshot of it ought to last a while)
|
||||
|
||||
class PasswordResetFormNoActive(forms.Form):
|
||||
error_messages = {
|
||||
'unknown': _("That e-mail address doesn't have an associated "
|
||||
"user account. Are you sure you've registered?"),
|
||||
'unusable': _("The user account associated with this e-mail "
|
||||
"address cannot reset the password."),
|
||||
}
|
||||
email = forms.EmailField(label=_("E-mail"), max_length=75)
|
||||
|
||||
def clean_email(self):
|
||||
"""
|
||||
Validates that an active user exists with the given email address.
|
||||
"""
|
||||
email = self.cleaned_data["email"]
|
||||
#The line below contains the only change, removing is_active=True
|
||||
self.users_cache = User.objects.filter(email__iexact=email)
|
||||
if not len(self.users_cache):
|
||||
raise forms.ValidationError(self.error_messages['unknown'])
|
||||
if any((user.password == UNUSABLE_PASSWORD)
|
||||
for user in self.users_cache):
|
||||
raise forms.ValidationError(self.error_messages['unusable'])
|
||||
return email
|
||||
|
||||
def save(self, domain_override=None,
|
||||
subject_template_name='registration/password_reset_subject.txt',
|
||||
email_template_name='registration/password_reset_email.html',
|
||||
use_https=False, token_generator=default_token_generator,
|
||||
from_email=None, request=None):
|
||||
"""
|
||||
Generates a one-use only link for resetting password and sends to the
|
||||
user.
|
||||
"""
|
||||
from django.core.mail import send_mail
|
||||
for user in self.users_cache:
|
||||
if not domain_override:
|
||||
current_site = get_current_site(request)
|
||||
site_name = current_site.name
|
||||
domain = current_site.domain
|
||||
else:
|
||||
site_name = domain = domain_override
|
||||
c = {
|
||||
'email': user.email,
|
||||
'domain': domain,
|
||||
'site_name': site_name,
|
||||
'uid': int_to_base36(user.id),
|
||||
'user': user,
|
||||
'token': token_generator.make_token(user),
|
||||
'protocol': use_https and 'https' or 'http',
|
||||
}
|
||||
subject = loader.render_to_string(subject_template_name, c)
|
||||
# Email subject *must not* contain newlines
|
||||
subject = ''.join(subject.splitlines())
|
||||
email = loader.render_to_string(email_template_name, c)
|
||||
send_mail(subject, email, from_email, [user.email])
|
||||
|
||||
@@ -11,9 +11,9 @@ import time
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout, authenticate, login
|
||||
from django.contrib.auth.forms import PasswordResetForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.views import password_reset_confirm
|
||||
from django.core.cache import cache
|
||||
from django.core.context_processors import csrf
|
||||
from django.core.mail import send_mail
|
||||
@@ -24,6 +24,7 @@ from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbid
|
||||
from django.shortcuts import redirect
|
||||
from django_future.csrf import ensure_csrf_cookie
|
||||
from django.utils.http import cookie_date
|
||||
from django.utils.http import base36_to_int
|
||||
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from bs4 import BeautifulSoup
|
||||
@@ -34,6 +35,8 @@ from student.models import (Registration, UserProfile, TestCenterUser, TestCente
|
||||
CourseEnrollment, unique_id_for_user,
|
||||
get_testcenter_registration, CourseEnrollmentAllowed)
|
||||
|
||||
from student.forms import PasswordResetFormNoActive
|
||||
|
||||
from certificates.models import CertificateStatuses, certificate_status_for_student
|
||||
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
@@ -962,17 +965,7 @@ def password_reset(request):
|
||||
if request.method != "POST":
|
||||
raise Http404
|
||||
|
||||
# By default, Django doesn't allow Users with is_active = False to reset their passwords,
|
||||
# but this bites people who signed up a long time ago, never activated, and forgot their
|
||||
# password. So for their sake, we'll auto-activate a user for whom password_reset is called.
|
||||
try:
|
||||
user = User.objects.get(email=request.POST['email'])
|
||||
user.is_active = True
|
||||
user.save()
|
||||
except:
|
||||
log.exception("Tried to auto-activate user to enable password reset, but failed.")
|
||||
|
||||
form = PasswordResetForm(request.POST)
|
||||
form = PasswordResetFormNoActive(request.POST)
|
||||
if form.is_valid():
|
||||
form.save(use_https=request.is_secure(),
|
||||
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||
@@ -984,6 +977,20 @@ def password_reset(request):
|
||||
return HttpResponse(json.dumps({'success': False,
|
||||
'error': 'Invalid e-mail'}))
|
||||
|
||||
def password_reset_confirm_wrapper(request, uidb36=None, token=None):
|
||||
''' A wrapper around django.contrib.auth.views.password_reset_confirm.
|
||||
Needed because we want to set the user as active at this step.
|
||||
'''
|
||||
#cribbed from django.contrib.auth.views.password_reset_confirm
|
||||
try:
|
||||
uid_int = base36_to_int(uidb36)
|
||||
user = User.objects.get(id=uid_int)
|
||||
user.is_active = True
|
||||
user.save()
|
||||
except (ValueError, User.DoesNotExist):
|
||||
pass
|
||||
return password_reset_confirm(request, uidb36=uidb36, token=token)
|
||||
|
||||
|
||||
def reactivation_email_for_user(user):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user