Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0f60c0e
Text/html alternative added for recovery email
ellmetha Oct 26, 2014
9af82f9
Fixed PEP8 compliance (E501)
ellmetha Oct 26, 2014
73fb549
Base email template updated to properly handle secure http
ellmetha Nov 18, 2014
342ac50
Updated spanish translation
ezegolub Apr 10, 2015
bfae6dd
Generating link both from user.pk and user.password to mitigate issue…
dat-boris Apr 15, 2015
46d6f2c
Tidy up password hashing call
dat-boris Apr 15, 2015
b4e45c9
Use django hasher to avoid handling hashlib different across py27 and…
dat-boris Apr 15, 2015
62aa3ab
adding the ability to change case sensitivity with a django setting
pnurkkala Jan 18, 2016
762a969
added logic to show an error page/msg if email cannot be sent as repo…
Mar 24, 2016
ad9b1fe
removed/cleaned django.po.original
Mar 24, 2016
15eb17f
removed sekizai_tags from include, which broke the travis build
Mar 28, 2016
22567e8
fixed test cases to work with optional captchas, also unified error m…
Mar 28, 2016
c1b9563
added blank models.py to work with Django 1.5 or lower; Added COLON_S…
Mar 28, 2016
074a35d
fixed some lint errors
Mar 28, 2016
395f5a1
restored custom user
Mar 28, 2016
bae7e50
fixed lint errors
Mar 28, 2016
95e7357
dummy changes to invoke lint, which was not run due to travis server …
Mar 28, 2016
fe83702
locale: removed old zh/, create link zh to zh-hans.
Mar 29, 2016
9f50f35
Merge branch 'master' of https://github.com/zhangguiyu/django-passwor…
Mar 29, 2016
ce5f13c
Adding method used to customize how to get the user into subclasses.
alexsilva Aug 31, 2017
9277411
Ignore ide files.
alexsilva Aug 31, 2017
ea97da6
Merge branch 'master' of https://github.com/ellmetha/django-password-…
alexsilva Aug 31, 2017
f79bb52
Merge remote-tracking branch 'upstream/patch-1' into dev
alexsilva Aug 31, 2017
168bf4d
Merge remote-tracking branch 'upstream/master' into dev
alexsilva Aug 31, 2017
2d8de16
merge upstream.
alexsilva Aug 31, 2017
65d8b63
bug fix merge.
alexsilva Aug 31, 2017
be56e71
Moving compatibility code.
alexsilva Aug 31, 2017
e4952c3
Moving compatibility code.
alexsilva Aug 31, 2017
f759048
Merge remote-tracking branch 'upstream/master' into dev
alexsilva Sep 1, 2017
d6338e5
Up version.
alexsilva Sep 1, 2017
c2a8d5b
Fix go to link.
alexsilva Sep 1, 2017
f71dae3
Changing logic to work with captcha.
alexsilva Sep 1, 2017
3546817
Up version.
alexsilva Sep 1, 2017
519990f
Add package compat.
alexsilva Sep 16, 2020
694802f
Fix import url reverse to django2.
alexsilva Sep 16, 2020
5c1018b
v0.9.0
alexsilva Sep 22, 2020
174f9a3
Replace 'ugettext_lazy' with 'gettext_lazy'.
alexsilva Apr 25, 2024
0d0769b
#3122: remoção de 'providing_args'.
alexsilva Apr 25, 2024
ee22edb
update coding.
alexsilva Sep 20, 2024
fdc5f2b
v1.0.0
alexsilva Sep 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ docs/_build
*.pyc
.tox
build
.idea
2 changes: 2 additions & 0 deletions docs/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ What you get

* Password reset links that expire in two days (configurable).

* Optionally invoke a captcha in the password reset page if django-simple-captcha (0.5.1 or higher) is installed and configured.

What you can do
---------------

Expand Down
4 changes: 4 additions & 0 deletions docs/views.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Attributes
* ``email_template_name``: the template to use for sending the reset link by
email. Default: ``password_reset/recovery_email.txt``.

* ``email_html_template_name``: the HTML template to use for sending the reset link by
email. The content of this template will be sent as the text/html content type alternative.
Default: ``password_reset/recovery_email.html``.

* ``email_subject_template_name``: the template to use for generating the
email subject. Defaults to ``password_reset/recovery_email_subject.txt``.

Expand Down
2 changes: 1 addition & 1 deletion password_reset/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.0'
__version__ = '1.0.0'
34 changes: 34 additions & 0 deletions password_reset/compat/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# coding=utf-8

def get_user_model():
"""
Returns the User model that is active in this project.
"""
try:
from django.contrib.auth import get_user_model
User = get_user_model()
except ImportError:
from django.contrib.auth.models import User
return User


def get_username(user):
"""
Returns the name of the username field
:param user: User object instance
:return: str
"""
username_field = getattr(user, 'USERNAME_FIELD', 'username')
return getattr(user, username_field)


def get_current_site(*args, **kwargs):
"""
Checks if contrib.sites is installed and returns either the current
``Site`` object or a ``RequestSite`` object based on the request.
"""
try:
from django.contrib.sites.shortcuts import get_current_site as current_site
except ImportError:
from django.contrib.sites.models import get_current_site as current_site
return current_site(*args, **kwargs)
6 changes: 6 additions & 0 deletions password_reset/compat/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# coding=utf-8

try:
from django.urls import reverse, reverse_lazy, NoReverseMatch
except ImportError:
from django.core.urlresolvers import reverse, reverse_lazy, NoReverseMatch
71 changes: 51 additions & 20 deletions password_reset/forms.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
from django import forms
from django.contrib.auth import get_user_model
from django.core.exceptions import ImproperlyConfigured
from django.core.validators import validate_email
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.conf import settings
from .compat import get_user_model

error_messages = {
'not_found': _("Sorry, this user doesn't exist."),
'password_mismatch': _("The two passwords didn't match."),
}

try:
# must be installed before.
if 'captcha' not in settings.INSTALLED_APPS:
raise ImproperlyConfigured("captcha is not installed.")

# uses django-simple-captcha
from captcha.fields import CaptchaField


class CaptchaForm(forms.Form):
captcha = CaptchaField(label=_('Captcha')) # Optional Captcha

def order_fields(self, field_order):
"""https://docs.djangoproject.com/en/1.9/ref/forms/api/#django.forms.Form.order_fields"""
# Put the captcha at the bottom of the form
field_name = "captcha"
if field_order is None:
field_order = self.fields.keys()
field_order.pop(field_order.index(field_name))
field_order.append(field_name)
return super(CaptchaForm, self).order_fields(field_order)

class PasswordRecoveryForm(forms.Form):
username_or_email = forms.CharField()

error_messages = {
'not_found': _("Sorry, this user doesn't exist."),
}
except (ImproperlyConfigured, ImportError):
CaptchaForm = forms.Form


class PasswordRecoveryForm(CaptchaForm):
username_or_email = forms.CharField()

def __init__(self, *args, **kwargs):
self.case_sensitive = kwargs.pop('case_sensitive', True)
Expand Down Expand Up @@ -52,17 +80,23 @@ def clean_username_or_email(self):

if recovery_only_active_users and not user_is_active:
raise forms.ValidationError(_("Sorry, inactive users can't "
"recover their password."))
"recover their password."))

return username

def get_user(self, *args, **kwargs):
""" Method used to customize how to get the user into subclasses.
:rtype: User object
"""
return get_user_model()._default_manager.get(*args, **kwargs)

def get_user_by_username(self, username):
key = 'username__%sexact' % ('' if self.case_sensitive else 'i')
User = get_user_model()
try:
user = User._default_manager.get(**{key: username})
user = self.get_user(**{key: username})
except User.DoesNotExist:
raise forms.ValidationError(self.error_messages['not_found'],
raise forms.ValidationError(error_messages['not_found'],
code='not_found')
return user

Expand All @@ -71,24 +105,25 @@ def get_user_by_email(self, email):
key = 'email__%sexact' % ('' if self.case_sensitive else 'i')
User = get_user_model()
try:
user = User._default_manager.get(**{key: email})
user = self.get_user(**{key: email})
except User.DoesNotExist:
raise forms.ValidationError(self.error_messages['not_found'],
raise forms.ValidationError(error_messages['not_found'],
code='not_found')
return user

def get_user_by_both(self, username):
key = '__%sexact'
key = key % '' if self.case_sensitive else key % 'i'

def f(field):
def f(field): # to satisfy lint in Travis auto build on Github
return Q(**{field + key: username})

filters = f('username') | f('email')
User = get_user_model()
try:
user = User._default_manager.get(filters)
user = self.get_user(filters)
except User.DoesNotExist:
raise forms.ValidationError(self.error_messages['not_found'],
raise forms.ValidationError(error_messages['not_found'],
code='not_found')
except User.MultipleObjectsReturned:
raise forms.ValidationError(_("Unable to find user."))
Expand All @@ -106,10 +141,6 @@ class PasswordResetForm(forms.Form):
widget=forms.PasswordInput,
)

error_messages = {
'password_mismatch': _("The two passwords didn't match."),
}

def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(PasswordResetForm, self).__init__(*args, **kwargs)
Expand All @@ -119,7 +150,7 @@ def clean_password2(self):
password2 = self.cleaned_data['password2']
if not password1 == password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
error_messages['password_mismatch'],
code='password_mismatch')
return password2

Expand Down
2 changes: 1 addition & 1 deletion password_reset/locale/es/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,5 @@ msgid ""
"An email was sent to <strong>%(email)s</strong> %(ago)s ago. Use the link in "
"it to set a new password."
msgstr ""
"Un email ha sido enviado a <strong>%(email)s</strong> hace %(ago)s minutos. "
"Un email ha sido enviado a <strong>%(email)s</strong> hace %(ago)s. "
"Use el enlace recibido para recuperar su clave"
1 change: 1 addition & 0 deletions password_reset/locale/zh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
zh-hans
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-23 10:01+0800\n"
"POT-Creation-Date: 2016-02-05 16:48+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -17,35 +17,43 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: forms.py:26
#: forms.py:14
msgid "Captcha"
msgstr "认证码"

#: forms.py:17
msgid "Sorry, this user doesn't exist."
msgstr "抱歉,用户名不存在."

#: forms.py:34
msgid "Username"
msgstr "用户名"

#: forms.py:27
#: forms.py:35
msgid "Email"
msgstr "邮箱"

#: forms.py:28
#: forms.py:36
msgid "Username or Email"
msgstr "用户名或者邮箱"

#: forms.py:48 forms.py:58 forms.py:70
msgid "Sorry, this user doesn't exist."
msgstr "抱歉,用户名不存在."
#: forms.py:58
msgid "Sorry, inactive users can't recover their password."
msgstr "非常抱歉,非活跃用户无法重置密码。"

#: forms.py:72
#: forms.py:96
msgid "Unable to find user."
msgstr "找不到指定用户"

#: forms.py:78
#: forms.py:103
msgid "New password"
msgstr "新密码"

#: forms.py:82
#: forms.py:107
msgid "New password (confirm)"
msgstr "新密码(确认)"
msgstr "新密码(确认)"

#: forms.py:94
#: forms.py:112
msgid "The two passwords didn't match."
msgstr "两次输入的密码不一致"

Expand All @@ -57,19 +65,19 @@ msgstr "设置新密码"
msgid ""
"Your password has successfully been reset. You can use it right now on the "
"login page."
msgstr "您的密码已经重设成功,现在可以登录了."
msgstr "您的密码已经重设成功现在可以登录了"

#: templates/password_reset/recovery_email.txt:1
#, python-format
msgid "Dear %(username)s,"
msgstr "您好 %(username)s,"
msgstr "%(username)s,您好:"

#: templates/password_reset/recovery_email.txt:3
#, python-format
msgid ""
"You -- or someone pretending to be you -- has requested a password reset on "
"%(domain)s."
msgstr "您或者其它的人在 %(domain)s 申请了密码重置."
msgstr "您或某人在 %(domain)s 申请了密码重置"

#: templates/password_reset/recovery_email.txt:5
msgid "You can set your new password by following this link:"
Expand All @@ -79,18 +87,30 @@ msgstr "您可以通过以下链接重置密码:"
msgid ""
"If you don't want to reset your password, simply ignore this email and it "
"will stay unchanged."
msgstr "如果您不想重设密码,可以忽略此邮箱."
msgstr "若不想重设密码,可以忽略此邮件。"

#: templates/password_reset/recovery_email.txt:11
msgid "Yours Truly"
msgstr "感谢您的惠顾"

#: templates/password_reset/recovery_email.txt:12
msgid "Administrator"
msgstr "管理者"

#: templates/password_reset/recovery_email_subject.txt:1
#, python-format
msgid "Password recovery on %(domain)s"
msgstr " %(domain)s 上重设密码"
msgstr "重设 %(domain)s 密码"

#: templates/password_reset/recovery_form.html:5
msgid "Password recovery"
msgstr "重新设置密码"

#: templates/password_reset/recovery_form.html:11
#: templates/password_reset/recovery_form.html:8
msgid "Recover Password"
msgstr "重设密码"

#: templates/password_reset/recovery_form.html:60
msgid "Recover my password"
msgstr "重设密码"

Expand All @@ -99,7 +119,8 @@ msgstr "重设密码"
msgid ""
"Sorry, this password reset link is invalid. You can still <a href="
"\"%(recovery_url)s\">request a new one</a>."
msgstr "抱歉,链接已经失效,您可以在 <a href=""\"%(recovery_url)s\">请求一个新链接</a>."
msgstr ""
"抱歉,链接已经失效,您可以在 <a href=\"%(recovery_url)s\">请求一个新链接</a>."

#: templates/password_reset/reset.html:7
#, python-format
Expand All @@ -114,9 +135,26 @@ msgstr "设置新密码"
msgid "Password recovery sent"
msgstr "发送重设密码"

#: templates/password_reset/reset_sent.html:7
#: templates/password_reset/reset_sent.html:8
#, python-format
msgid ""
"An email was sent to <strong>%(email)s</strong> %(ago)s ago. Use the link in "
"it to set a new password."
msgstr "已经在%(ago)s以前向您的邮箱 <strong>%(email)s</strong>发送了邮件,根据邮件提示重新设置您的新密码."
msgstr ""
"已经在%(ago)s以前向您的邮箱 <strong>%(email)s</strong> 发送了邮件,请根据邮件"
"提示重新设置您的新密码."

#: templates/password_reset/reset_sent.html:11
#: templates/password_reset/reset_sent_failed.html:9
msgid "Return to Main Page"
msgstr "回主页"

#: templates/password_reset/reset_sent_failed.html:4
msgid "Password recovery NOT successful"
msgstr "发送重设密码"

#: templates/password_reset/reset_sent_failed.html:7
msgid ""
"The email for this registered user is invalid, password reset information "
"cannot be sent. Please contact our administrator for assistance."
msgstr "此用户电邮地址无法接收密码重置信息。欢迎联系我们的客服部门。"
Binary file removed password_reset/locale/zh/LC_MESSAGES/django.mo
Binary file not shown.
1 change: 1 addition & 0 deletions password_reset/locale/zh_Hans
Empty file added password_reset/models.py
Empty file.
4 changes: 1 addition & 3 deletions password_reset/signals.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
from django.dispatch import Signal

# signal sent when users successfully recover their passwords
user_recovers_password = Signal(
providing_args=['user', 'request']
)
user_recovers_password = Signal()
Loading