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:
Jannis Leidel 2011-06-19 11:24:39 +00:00
parent 63f9b67129
commit 656360c240
9 changed files with 84 additions and 57 deletions

View File

@ -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 *

View File

@ -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"
} }
}, },

View File

@ -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):
""" """

View File

@ -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 ""

View File

@ -0,0 +1,3 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %}
{% endautoescape %}

View File

@ -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

View File

@ -0,0 +1 @@
{% autoescape off %}Custom password reset on {{ site_name }}{% endautoescape %}

View File

@ -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:

View File

@ -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`.