mirror of https://github.com/django/django.git
Fixed #12202 -- Removed hardcoded password reset subject and added a subject_template_name parameter to the password_reset view. Thanks, Ramiro Morales, Claude Paroz and agabel.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16438 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
63f9b67129
commit
656360c240
|
@ -17,6 +17,7 @@ recursive-include django/contrib/admin/templates *
|
||||||
recursive-include django/contrib/admin/media *
|
recursive-include django/contrib/admin/media *
|
||||||
recursive-include django/contrib/admindocs/templates *
|
recursive-include django/contrib/admindocs/templates *
|
||||||
recursive-include django/contrib/auth/fixtures *
|
recursive-include django/contrib/auth/fixtures *
|
||||||
|
recursive-include django/contrib/auth/templates *
|
||||||
recursive-include django/contrib/auth/tests/templates *
|
recursive-include django/contrib/auth/tests/templates *
|
||||||
recursive-include django/contrib/comments/templates *
|
recursive-include django/contrib/comments/templates *
|
||||||
recursive-include django/contrib/databrowse/templates *
|
recursive-include django/contrib/databrowse/templates *
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"groups": [],
|
"groups": [],
|
||||||
"user_permissions": [],
|
"user_permissions": [],
|
||||||
"password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161",
|
"password": "sha1$6efc0$f93efe9fd7542f25a7be94871ea45aa95de57161",
|
||||||
"email": "testclient@example.com",
|
"email": "testclient2@example.com",
|
||||||
"date_joined": "2006-12-17 07:03:31"
|
"date_joined": "2006-12-17 07:03:31"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -120,8 +120,11 @@ class PasswordResetForm(forms.Form):
|
||||||
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
|
raise forms.ValidationError(_("That e-mail address doesn't have an associated user account. Are you sure you've registered?"))
|
||||||
return email
|
return email
|
||||||
|
|
||||||
def save(self, domain_override=None, email_template_name='registration/password_reset_email.html',
|
def save(self, domain_override=None,
|
||||||
use_https=False, token_generator=default_token_generator, from_email=None, request=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
|
Generates a one-use only link for resetting password and sends to the user
|
||||||
"""
|
"""
|
||||||
|
@ -133,7 +136,6 @@ class PasswordResetForm(forms.Form):
|
||||||
domain = current_site.domain
|
domain = current_site.domain
|
||||||
else:
|
else:
|
||||||
site_name = domain = domain_override
|
site_name = domain = domain_override
|
||||||
t = loader.get_template(email_template_name)
|
|
||||||
c = {
|
c = {
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'domain': domain,
|
'domain': domain,
|
||||||
|
@ -143,8 +145,11 @@ class PasswordResetForm(forms.Form):
|
||||||
'token': token_generator.make_token(user),
|
'token': token_generator.make_token(user),
|
||||||
'protocol': use_https and 'https' or 'http',
|
'protocol': use_https and 'https' or 'http',
|
||||||
}
|
}
|
||||||
send_mail(_("Password reset on %s") % site_name,
|
subject = loader.render_to_string(subject_template_name, c)
|
||||||
t.render(Context(c)), from_email, [user.email])
|
# 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])
|
||||||
|
|
||||||
class SetPasswordForm(forms.Form):
|
class SetPasswordForm(forms.Form):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -4,7 +4,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Django\n"
|
"Project-Id-Version: Django\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2011-03-15 13:14-0400\n"
|
"POT-Creation-Date: 2011-06-19 13:08+0200\n"
|
||||||
"PO-Revision-Date: 2010-05-13 15:35+0200\n"
|
"PO-Revision-Date: 2010-05-13 15:35+0200\n"
|
||||||
"Last-Translator: Django team\n"
|
"Last-Translator: Django team\n"
|
||||||
"Language-Team: English <en@li.org>\n"
|
"Language-Team: English <en@li.org>\n"
|
||||||
|
@ -12,27 +12,27 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: admin.py:28
|
#: admin.py:29
|
||||||
msgid "Personal info"
|
msgid "Personal info"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:29
|
#: admin.py:30
|
||||||
msgid "Permissions"
|
msgid "Permissions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:30
|
#: admin.py:31
|
||||||
msgid "Important dates"
|
msgid "Important dates"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:31
|
#: admin.py:32
|
||||||
msgid "Groups"
|
msgid "Groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:113
|
#: admin.py:116
|
||||||
msgid "Password changed successfully."
|
msgid "Password changed successfully."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: admin.py:123
|
#: admin.py:126
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Change password: %s"
|
msgid "Change password: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -49,7 +49,7 @@ msgstr ""
|
||||||
msgid "This value may contain only letters, numbers and @/./+/-/_ characters."
|
msgid "This value may contain only letters, numbers and @/./+/-/_ characters."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:17 forms.py:67 forms.py:193
|
#: forms.py:17 forms.py:67 forms.py:201
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ msgstr ""
|
||||||
msgid "A user with that username already exists."
|
msgid "A user with that username already exists."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:37 forms.py:163 forms.py:205
|
#: forms.py:37 forms.py:171 forms.py:213
|
||||||
msgid "The two password fields didn't match."
|
msgid "The two password fields didn't match."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -89,154 +89,150 @@ msgstr ""
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:117
|
#: forms.py:120
|
||||||
msgid ""
|
msgid ""
|
||||||
"That e-mail address doesn't have an associated user account. Are you sure "
|
"That e-mail address doesn't have an associated user account. Are you sure "
|
||||||
"you've registered?"
|
"you've registered?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:143
|
#: forms.py:159
|
||||||
#, python-format
|
|
||||||
msgid "Password reset on %s"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: forms.py:151
|
|
||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:152
|
#: forms.py:160
|
||||||
msgid "New password confirmation"
|
msgid "New password confirmation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:177
|
#: forms.py:185
|
||||||
msgid "Old password"
|
msgid "Old password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:185
|
#: forms.py:193
|
||||||
msgid "Your old password was entered incorrectly. Please enter it again."
|
msgid "Your old password was entered incorrectly. Please enter it again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: forms.py:194
|
#: forms.py:202
|
||||||
msgid "Password (again)"
|
msgid "Password (again)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:76 models.py:104
|
#: models.py:77 models.py:105
|
||||||
msgid "name"
|
msgid "name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:78
|
#: models.py:79
|
||||||
msgid "codename"
|
msgid "codename"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:82
|
#: models.py:83
|
||||||
msgid "permission"
|
msgid "permission"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:83 models.py:105
|
#: models.py:84 models.py:106
|
||||||
msgid "permissions"
|
msgid "permissions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:108
|
#: models.py:109
|
||||||
msgid "group"
|
msgid "group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:109 models.py:216
|
#: models.py:110 models.py:217
|
||||||
msgid "groups"
|
msgid "groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:206
|
#: models.py:207
|
||||||
msgid "username"
|
msgid "username"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:206
|
#: models.py:207
|
||||||
msgid ""
|
msgid ""
|
||||||
"Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"
|
"Required. 30 characters or fewer. Letters, numbers and @/./+/-/_ characters"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:207
|
#: models.py:208
|
||||||
msgid "first name"
|
msgid "first name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:208
|
#: models.py:209
|
||||||
msgid "last name"
|
msgid "last name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:209
|
#: models.py:210
|
||||||
msgid "e-mail address"
|
msgid "e-mail address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:210
|
#: models.py:211
|
||||||
msgid "password"
|
msgid "password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:210
|
#: models.py:211
|
||||||
msgid ""
|
msgid ""
|
||||||
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
|
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
|
||||||
"password form</a>."
|
"password form</a>."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:211
|
#: models.py:212
|
||||||
msgid "staff status"
|
msgid "staff status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:211
|
#: models.py:212
|
||||||
msgid "Designates whether the user can log into this admin site."
|
msgid "Designates whether the user can log into this admin site."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:212
|
#: models.py:213
|
||||||
msgid "active"
|
msgid "active"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:212
|
#: models.py:213
|
||||||
msgid ""
|
msgid ""
|
||||||
"Designates whether this user should be treated as active. Unselect this "
|
"Designates whether this user should be treated as active. Unselect this "
|
||||||
"instead of deleting accounts."
|
"instead of deleting accounts."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:213
|
#: models.py:214
|
||||||
msgid "superuser status"
|
msgid "superuser status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:213
|
#: models.py:214
|
||||||
msgid ""
|
msgid ""
|
||||||
"Designates that this user has all permissions without explicitly assigning "
|
"Designates that this user has all permissions without explicitly assigning "
|
||||||
"them."
|
"them."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:214
|
#: models.py:215
|
||||||
msgid "last login"
|
msgid "last login"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:215
|
#: models.py:216
|
||||||
msgid "date joined"
|
msgid "date joined"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:217
|
#: models.py:218
|
||||||
msgid ""
|
msgid ""
|
||||||
"In addition to the permissions manually assigned, this user will also get "
|
"In addition to the permissions manually assigned, this user will also get "
|
||||||
"all permissions granted to each group he/she is in."
|
"all permissions granted to each group he/she is in."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:218
|
#: models.py:219
|
||||||
msgid "user permissions"
|
msgid "user permissions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:222
|
#: models.py:223
|
||||||
msgid "user"
|
msgid "user"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:223
|
#: models.py:224
|
||||||
msgid "users"
|
msgid "users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: models.py:406
|
#: views.py:93
|
||||||
msgid "message"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: views.py:91
|
|
||||||
msgid "Logged out"
|
msgid "Logged out"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: management/commands/createsuperuser.py:23
|
#: management/commands/createsuperuser.py:24
|
||||||
msgid "Enter a valid e-mail address."
|
msgid "Enter a valid e-mail address."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/registration/password_reset_subject.txt:2
|
||||||
|
#, python-format
|
||||||
|
msgid "Password reset on %(site_name)s"
|
||||||
|
msgstr ""
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% load i18n %}{% autoescape off %}
|
||||||
|
{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %}
|
||||||
|
{% endautoescape %}
|
|
@ -1,3 +1,7 @@
|
||||||
|
from __future__ import with_statement
|
||||||
|
import os
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core import mail
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm
|
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
@ -251,6 +255,15 @@ class PasswordResetFormTest(TestCase):
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
self.assertEqual(form.cleaned_data['email'], email)
|
self.assertEqual(form.cleaned_data['email'], email)
|
||||||
|
|
||||||
|
def test_custom_email_subject(self):
|
||||||
|
template_path = os.path.join(os.path.dirname(__file__), 'templates')
|
||||||
|
with self.settings(TEMPLATE_DIRS=(template_path,)):
|
||||||
|
data = {'email': 'testclient@example.com'}
|
||||||
|
form = PasswordResetForm(data)
|
||||||
|
self.assertTrue(form.is_valid())
|
||||||
|
form.save()
|
||||||
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
|
self.assertEqual(mail.outbox[0].subject, u'Custom password reset on example.com')
|
||||||
|
|
||||||
def test_bug_5605(self):
|
def test_bug_5605(self):
|
||||||
# bug #5605, preserve the case of the user name (before the @ in the
|
# bug #5605, preserve the case of the user name (before the @ in the
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{% autoescape off %}Custom password reset on {{ site_name }}{% endautoescape %}
|
|
@ -135,6 +135,7 @@ def redirect_to_login(next, login_url=None,
|
||||||
def password_reset(request, is_admin_site=False,
|
def password_reset(request, is_admin_site=False,
|
||||||
template_name='registration/password_reset_form.html',
|
template_name='registration/password_reset_form.html',
|
||||||
email_template_name='registration/password_reset_email.html',
|
email_template_name='registration/password_reset_email.html',
|
||||||
|
subject_template_name='registration/password_reset_subject.txt',
|
||||||
password_reset_form=PasswordResetForm,
|
password_reset_form=PasswordResetForm,
|
||||||
token_generator=default_token_generator,
|
token_generator=default_token_generator,
|
||||||
post_reset_redirect=None,
|
post_reset_redirect=None,
|
||||||
|
@ -151,6 +152,7 @@ def password_reset(request, is_admin_site=False,
|
||||||
'token_generator': token_generator,
|
'token_generator': token_generator,
|
||||||
'from_email': from_email,
|
'from_email': from_email,
|
||||||
'email_template_name': email_template_name,
|
'email_template_name': email_template_name,
|
||||||
|
'subject_template_name': subject_template_name,
|
||||||
'request': request,
|
'request': request,
|
||||||
}
|
}
|
||||||
if is_admin_site:
|
if is_admin_site:
|
||||||
|
|
|
@ -964,6 +964,12 @@ includes a few other useful built-in views located in
|
||||||
generating the email with the new password. This will default to
|
generating the email with the new password. This will default to
|
||||||
:file:`registration/password_reset_email.html` if not supplied.
|
:file:`registration/password_reset_email.html` if not supplied.
|
||||||
|
|
||||||
|
* ``subject_template_name``: The full name of a template to use for
|
||||||
|
the subject of the email with the new password. This will default
|
||||||
|
to :file:`registration/password_reset_subject.txt` if not supplied.
|
||||||
|
|
||||||
|
.. versionadded:: 1.4
|
||||||
|
|
||||||
* ``password_reset_form``: Form that will be used to set the password.
|
* ``password_reset_form``: Form that will be used to set the password.
|
||||||
Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`.
|
Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue