ソースを参照

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
Jannis Leidel 13 年 前
コミット
656360c240

+ 1 - 0
MANIFEST.in

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

+ 1 - 1
django/contrib/auth/fixtures/authtestdata.json

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

+ 10 - 5
django/contrib/auth/forms.py

@@ -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',
-             use_https=False, token_generator=default_token_generator, from_email=None, request=None):
+    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
         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,
-                t.render(Context(c)), from_email, [user.email])
+            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])
 
 
 class SetPasswordForm(forms.Form):
 class SetPasswordForm(forms.Form):
     """
     """

+ 47 - 51
django/contrib/auth/locale/en/LC_MESSAGES/django.po

@@ -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
-#, python-format
-msgid "Password reset on %s"
-msgstr ""
-
-#: forms.py:151
+#: forms.py:159
 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
-msgid "message"
-msgstr ""
-
-#: views.py:91
+#: views.py:93
 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 ""

+ 3 - 0
django/contrib/auth/templates/registration/password_reset_subject.txt

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

+ 13 - 0
django/contrib/auth/tests/forms.py

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

+ 1 - 0
django/contrib/auth/tests/templates/registration/password_reset_subject.txt

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

+ 2 - 0
django/contrib/auth/views.py

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

+ 6 - 0
docs/topics/auth.txt

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