From 7ad0e32027b37a5be3a4cadbe4a94582fb521ef7 Mon Sep 17 00:00:00 2001
From: Oliver Zhou
Date: Wed, 12 Jul 2017 00:03:48 -0700
Subject: [PATCH 1/6] Add reregistration option : conf.py configurations to
control email/response, UserReregistrationEmailFactory, override
RegistrationView.create(), add RegistrationView.send_reregistration_email()
---
djoser/conf.py | 2 ++
djoser/serializers.py | 1 -
.../templates/reregistration_email_body.html | 17 ++++++++++++++
.../templates/reregistration_email_body.txt | 14 ++++++++++++
.../reregistration_email_subject.txt | 3 +++
djoser/utils.py | 14 ++++++++++++
djoser/views.py | 22 +++++++++++++++++++
7 files changed, 72 insertions(+), 1 deletion(-)
create mode 100644 djoser/templates/reregistration_email_body.html
create mode 100644 djoser/templates/reregistration_email_body.txt
create mode 100644 djoser/templates/reregistration_email_subject.txt
diff --git a/djoser/conf.py b/djoser/conf.py
index 5c3a036a..785e0fce 100644
--- a/djoser/conf.py
+++ b/djoser/conf.py
@@ -15,6 +15,7 @@
'USE_HTML_EMAIL_TEMPLATES': False,
'SEND_ACTIVATION_EMAIL': False,
'SEND_CONFIRMATION_EMAIL': False,
+ 'SEND_REREGISTRATION_EMAIL': False,
'SET_PASSWORD_RETYPE': False,
'SET_USERNAME_RETYPE': False,
'PASSWORD_RESET_CONFIRM_RETYPE': False,
@@ -38,6 +39,7 @@
},
'LOGOUT_ON_PASSWORD_CHANGE': False,
'USER_EMAIL_FIELD_NAME': 'email',
+ 'REREGISTRATION_SHOW_RESPONSE': True,
}
SETTINGS_TO_IMPORT = ['TOKEN_MODEL']
diff --git a/djoser/serializers.py b/djoser/serializers.py
index 5d28b803..9c7771e4 100644
--- a/djoser/serializers.py
+++ b/djoser/serializers.py
@@ -72,7 +72,6 @@ def perform_create(self, validated_data):
return user
-
class LoginSerializer(serializers.Serializer):
password = serializers.CharField(
required=False, style={'input_type': 'password'}
diff --git a/djoser/templates/reregistration_email_body.html b/djoser/templates/reregistration_email_body.html
new file mode 100644
index 00000000..38a766ae
--- /dev/null
+++ b/djoser/templates/reregistration_email_body.html
@@ -0,0 +1,17 @@
+{% load i18n %}{% autoescape off %}
+
+
+
+{% blocktrans %}You're receiving this email because someone tried to reregister your user account at {{ site_name }}.{% endblocktrans %}
+
+{% trans "Please go to the following page and choose a new password:" %}
+{% block reset_link %}
+{{ protocol }}://{{ domain }}/{{ url }}
+{% endblock %}
+{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
+
+{% trans "Thanks for using our site!" %}
+
+{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
+
+{% endautoescape %}
diff --git a/djoser/templates/reregistration_email_body.txt b/djoser/templates/reregistration_email_body.txt
new file mode 100644
index 00000000..0cbd2658
--- /dev/null
+++ b/djoser/templates/reregistration_email_body.txt
@@ -0,0 +1,14 @@
+{% load i18n %}{% autoescape off %}
+{% blocktrans %}You're receiving this email because someone tried to reregister your user account at {{ site_name }}.{% endblocktrans %}
+
+{% trans "Please go to the following page and choose a new password:" %}
+{% block reset_link %}
+{{ protocol }}://{{ domain }}/{{ url }}
+{% endblock %}
+{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
+
+{% trans "Thanks for using our site!" %}
+
+{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
+
+{% endautoescape %}
diff --git a/djoser/templates/reregistration_email_subject.txt b/djoser/templates/reregistration_email_subject.txt
new file mode 100644
index 00000000..76085c94
--- /dev/null
+++ b/djoser/templates/reregistration_email_subject.txt
@@ -0,0 +1,3 @@
+{% load i18n %}{% autoescape off %}
+{% blocktrans %}Reregistration requested on {{ site_name }}{% endblocktrans %}
+{% endautoescape %}
\ No newline at end of file
diff --git a/djoser/utils.py b/djoser/utils.py
index 5a8f6eec..31bc3d77 100644
--- a/djoser/utils.py
+++ b/djoser/utils.py
@@ -143,6 +143,20 @@ def get_context(self):
return context
+class UserReregistrationEmailFactory(UserEmailFactoryBase):
+ subject_template_name = 'reregistration_email_subject.txt'
+ plain_body_template_name = 'reregistration_email_body.txt'
+ if settings.USE_HTML_EMAIL_TEMPLATES:
+ html_body_template_name = 'reregistration_email_body.html'
+
+ def get_context(self):
+ context = super(UserReregistrationEmailFactory, self).get_context()
+ context['url'] = settings.PASSWORD_RESET_CONFIRM_URL.format(
+ **context
+ )
+ return context
+
+
class UserConfirmationEmailFactory(UserEmailFactoryBase):
subject_template_name = 'confirmation_email_subject.txt'
plain_body_template_name = 'confirmation_email_body.txt'
diff --git a/djoser/views.py b/djoser/views.py
index 5ffb9b20..8b119b13 100644
--- a/djoser/views.py
+++ b/djoser/views.py
@@ -55,6 +55,21 @@ class RegistrationView(generics.CreateAPIView):
permissions.AllowAny,
)
+ def create(self, request, *args, **kwargs):
+ if not settings.REREGISTRATION_SHOW_RESPONSE:
+ try:
+ username_input = {User.USERNAME_FIELD: request.POST.get(User.USERNAME_FIELD)}
+ existing_user = User.objects.get(**username_input)
+ serializer = self.get_serializer(instance=existing_user)
+ if settings.SEND_REREGISTRATION_EMAIL:
+ self.send_reregistration_email(existing_user)
+ headers = self.get_success_headers(serializer.data)
+ return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
+ except User.DoesNotExist:
+ pass
+ response = super(RegistrationView, self).create(request, *args, **kwargs)
+ return response
+
def perform_create(self, serializer):
user = serializer.save()
signals.user_registered.send(
@@ -79,6 +94,13 @@ def send_confirmation_email(self, user):
email = email_factory.create()
email.send()
+ def send_reregistration_email(self, user):
+ email_factory = utils.UserReregistrationEmailFactory.from_request(
+ self.request, user=user
+ )
+ email = email_factory.create()
+ email.send()
+
class LoginView(utils.ActionViewMixin, generics.GenericAPIView):
"""
From b0581375c475acc5715993aa960f9e75b9a11545 Mon Sep 17 00:00:00 2001
From: Oliver Zhou
Date: Wed, 12 Jul 2017 03:13:23 -0700
Subject: [PATCH 2/6] Docs and additional email templates
---
.../templates/reregistration_email_body.html | 4 ++--
.../templates/reregistration_email_body.txt | 4 ++--
.../reregistration_inactive_email_body.html | 14 +++++++++++++
.../reregistration_inactive_email_body.txt | 11 ++++++++++
docs/source/settings.rst | 20 +++++++++++++++++++
5 files changed, 49 insertions(+), 4 deletions(-)
create mode 100644 djoser/templates/reregistration_inactive_email_body.html
create mode 100644 djoser/templates/reregistration_inactive_email_body.txt
diff --git a/djoser/templates/reregistration_email_body.html b/djoser/templates/reregistration_email_body.html
index 38a766ae..4a70b624 100644
--- a/djoser/templates/reregistration_email_body.html
+++ b/djoser/templates/reregistration_email_body.html
@@ -2,9 +2,9 @@
-{% blocktrans %}You're receiving this email because someone tried to reregister your user account at {{ site_name }}.{% endblocktrans %}
+{% blocktrans %}You're receiving this email because someone tried to reregister a user account with this email at {{ site_name }}.{% endblocktrans %}
-{% trans "Please go to the following page and choose a new password:" %}
+{% trans "If this wasn't you, please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}/{{ url }}
{% endblock %}
diff --git a/djoser/templates/reregistration_email_body.txt b/djoser/templates/reregistration_email_body.txt
index 0cbd2658..f6fd8c1f 100644
--- a/djoser/templates/reregistration_email_body.txt
+++ b/djoser/templates/reregistration_email_body.txt
@@ -1,7 +1,7 @@
{% load i18n %}{% autoescape off %}
-{% blocktrans %}You're receiving this email because someone tried to reregister your user account at {{ site_name }}.{% endblocktrans %}
+{% blocktrans %}You're receiving this email because someone tried to reregister a user account with this email at {{ site_name }}.{% endblocktrans %}
-{% trans "Please go to the following page and choose a new password:" %}
+{% trans "If this wasn't you, please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}/{{ url }}
{% endblock %}
diff --git a/djoser/templates/reregistration_inactive_email_body.html b/djoser/templates/reregistration_inactive_email_body.html
new file mode 100644
index 00000000..1d1941f3
--- /dev/null
+++ b/djoser/templates/reregistration_inactive_email_body.html
@@ -0,0 +1,14 @@
+{% load i18n %}{% autoescape off %}
+
+
+
+{% blocktrans %}You're receiving this email because someone tried to reregister your user account at {{ site_name }}.{% endblocktrans %}
+{% blocktrans %}Please find the previously sent activation email, or request a new one to properly set this account up{% endblocktrans %}
+
+{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
+
+{% trans "Thanks for using our site!" %}
+
+{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
+
+{% endautoescape %}
diff --git a/djoser/templates/reregistration_inactive_email_body.txt b/djoser/templates/reregistration_inactive_email_body.txt
new file mode 100644
index 00000000..f07fe4bd
--- /dev/null
+++ b/djoser/templates/reregistration_inactive_email_body.txt
@@ -0,0 +1,11 @@
+{% load i18n %}{% autoescape off %}
+{% blocktrans %}You're receiving this email because someone tried to reregister your user account at {{ site_name }}.{% endblocktrans %}
+{% blocktrans %}Please find the previously sent activation email, or request a new one to properly set this account up{% endblocktrans %}
+
+{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
+
+{% trans "Thanks for using our site!" %}
+
+{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
+
+{% endautoescape %}
diff --git a/docs/source/settings.rst b/docs/source/settings.rst
index e03428eb..a76bc4bb 100644
--- a/docs/source/settings.rst
+++ b/docs/source/settings.rst
@@ -56,6 +56,26 @@ If ``True``, register or activation endpoint will send confirmation email to use
**Default**: ``False``
+SEND_REREGISTRATION_EMAIL
+-------------------------
+
+If ``True``, register endpoint will send warning and reminder email to user.
+Only active users are able to reset their passwords (User.is_active is True).
+The email will ask the User to reset their password since someone is trying to
+re-register their account.
+If User.is_active is False, will send a warning
+
+**Default**: ``False``
+
+REREGISTRATION_SHOW_RESPONSE
+----------------------------
+
+If ``False`` (default), the ``/register/`` endpoint will always return
+a ``HTTP_201_CREATED`` response, as well as the UserSerializer serializer.data response
+of one of those users, so that it makes it difficult to distinguish if a User has this email
+
+**Default**: ``True``
+
ACTIVATION_URL
--------------
From 75f9e00de2c512a1ec88bdff2a8e7c282e519c22 Mon Sep 17 00:00:00 2001
From: Oliver Zhou
Date: Wed, 12 Jul 2017 03:26:20 -0700
Subject: [PATCH 3/6] Fix typo of extra tag
---
djoser/templates/reregistration_email_body.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/djoser/templates/reregistration_email_body.txt b/djoser/templates/reregistration_email_body.txt
index f6fd8c1f..902f62fb 100644
--- a/djoser/templates/reregistration_email_body.txt
+++ b/djoser/templates/reregistration_email_body.txt
@@ -1,5 +1,5 @@
{% load i18n %}{% autoescape off %}
-{% blocktrans %}You're receiving this email because someone tried to reregister a user account with this email at {{ site_name }}.{% endblocktrans %}
+{% blocktrans %}You're receiving this email because someone tried to reregister a user account with this email at {{ site_name }}.{% endblocktrans %}
{% trans "If this wasn't you, please go to the following page and choose a new password:" %}
{% block reset_link %}
From b3c694cd5381479438384db38dbbf919a71dcd5a Mon Sep 17 00:00:00 2001
From: Oliver Zhou
Date: Wed, 12 Jul 2017 03:31:14 -0700
Subject: [PATCH 4/6] Create the ability to send different kinds of emails to
Users who are either is_active or not, also allow for all combinations of
settings.REREGISTRATION_SHOW_RESPONSE and settings.SEND_REREGISTRATION_EMAIL
---
djoser/utils.py | 14 ++++++++++++++
djoser/views.py | 38 +++++++++++++++++++++++++++-----------
2 files changed, 41 insertions(+), 11 deletions(-)
diff --git a/djoser/utils.py b/djoser/utils.py
index 31bc3d77..ce1f4790 100644
--- a/djoser/utils.py
+++ b/djoser/utils.py
@@ -157,6 +157,20 @@ def get_context(self):
return context
+class UserReregistrationInactiveEmailFactory(UserEmailFactoryBase):
+ subject_template_name = 'reregistration_email_subject.txt'
+ plain_body_template_name = 'reregistration_inactive_email_body.txt'
+ if settings.USE_HTML_EMAIL_TEMPLATES:
+ html_body_template_name = 'reregistration_inactive_email_body.html'
+
+ def get_context(self):
+ context = super(UserReregistrationInactiveEmailFactory, self).get_context()
+ context['url'] = settings.PASSWORD_RESET_CONFIRM_URL.format(
+ **context
+ )
+ return context
+
+
class UserConfirmationEmailFactory(UserEmailFactoryBase):
subject_template_name = 'confirmation_email_subject.txt'
plain_body_template_name = 'confirmation_email_body.txt'
diff --git a/djoser/views.py b/djoser/views.py
index 8b119b13..e01cd558 100644
--- a/djoser/views.py
+++ b/djoser/views.py
@@ -54,19 +54,20 @@ class RegistrationView(generics.CreateAPIView):
permission_classes = (
permissions.AllowAny,
)
+ _users = None
def create(self, request, *args, **kwargs):
- if not settings.REREGISTRATION_SHOW_RESPONSE:
- try:
- username_input = {User.USERNAME_FIELD: request.POST.get(User.USERNAME_FIELD)}
- existing_user = User.objects.get(**username_input)
- serializer = self.get_serializer(instance=existing_user)
+ try:
+ email_users = self.get_email_users(request.POST.get('email'))
+ for user in email_users:
+ serializer = self.get_serializer(instance=user)
if settings.SEND_REREGISTRATION_EMAIL:
- self.send_reregistration_email(existing_user)
+ self.send_reregistration_email(user)
headers = self.get_success_headers(serializer.data)
+ if not settings.REREGISTRATION_SHOW_RESPONSE and email_users:
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
- except User.DoesNotExist:
- pass
+ except User.DoesNotExist:
+ pass
response = super(RegistrationView, self).create(request, *args, **kwargs)
return response
@@ -95,12 +96,27 @@ def send_confirmation_email(self, user):
email.send()
def send_reregistration_email(self, user):
- email_factory = utils.UserReregistrationEmailFactory.from_request(
- self.request, user=user
- )
+ if user.is_active:
+ email_factory = utils.UserReregistrationEmailFactory.from_request(
+ self.request, user=user
+ )
+ else:
+ email_factory = utils.UserReregistrationInactiveEmailFactory.from_request(
+ self.request, user=user
+ )
email = email_factory.create()
email.send()
+ def get_email_users(self, email):
+ if self._users is None:
+ email_field_name = get_user_email_field_name(User)
+ email_users_kwargs = {
+ email_field_name + '__iexact': email,
+ }
+ email_users = User._default_manager.filter(**email_users_kwargs)
+ self._users = [u for u in email_users if u.has_usable_password()]
+ return self._users
+
class LoginView(utils.ActionViewMixin, generics.GenericAPIView):
"""
From 12ef6540042b9d1e9830fa3103291d2ecca692c6 Mon Sep 17 00:00:00 2001
From: Oliver Zhou
Date: Wed, 12 Jul 2017 14:00:08 -0700
Subject: [PATCH 5/6] Use request.data instead of request.POST
---
djoser/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/djoser/views.py b/djoser/views.py
index e01cd558..14f93100 100644
--- a/djoser/views.py
+++ b/djoser/views.py
@@ -58,7 +58,7 @@ class RegistrationView(generics.CreateAPIView):
def create(self, request, *args, **kwargs):
try:
- email_users = self.get_email_users(request.POST.get('email'))
+ email_users = self.get_email_users(request.data.get('email'))
for user in email_users:
serializer = self.get_serializer(instance=user)
if settings.SEND_REREGISTRATION_EMAIL:
From 9a1e5d7751997a977792ff0bfe70802f10b83fd0 Mon Sep 17 00:00:00 2001
From: Oliver Zhou
Date: Fri, 21 Jul 2017 14:05:24 -0700
Subject: [PATCH 6/6] Address a few requests in PR : Rename
REREGISTRATION_SHOW_RESPONSE to REGISTRATION_SHOW_EMAIL_FOUND, use
"get_email_field_name" to properly find the User model's email field, rename
SEND_REREGISTRATION_EMAIL to RESEND_REGISTRATION_EMAIL
---
djoser/conf.py | 4 ++--
djoser/views.py | 13 +++++++------
docs/source/settings.rst | 6 +++---
3 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/djoser/conf.py b/djoser/conf.py
index 785e0fce..1a8b2c23 100644
--- a/djoser/conf.py
+++ b/djoser/conf.py
@@ -15,7 +15,7 @@
'USE_HTML_EMAIL_TEMPLATES': False,
'SEND_ACTIVATION_EMAIL': False,
'SEND_CONFIRMATION_EMAIL': False,
- 'SEND_REREGISTRATION_EMAIL': False,
+ 'RESEND_REGISTRATION_EMAIL': False,
'SET_PASSWORD_RETYPE': False,
'SET_USERNAME_RETYPE': False,
'PASSWORD_RESET_CONFIRM_RETYPE': False,
@@ -39,7 +39,7 @@
},
'LOGOUT_ON_PASSWORD_CHANGE': False,
'USER_EMAIL_FIELD_NAME': 'email',
- 'REREGISTRATION_SHOW_RESPONSE': True,
+ 'REGISTRATION_SHOW_EMAIL_FOUND': True,
}
SETTINGS_TO_IMPORT = ['TOKEN_MODEL']
diff --git a/djoser/views.py b/djoser/views.py
index 14f93100..470fcd87 100644
--- a/djoser/views.py
+++ b/djoser/views.py
@@ -58,13 +58,14 @@ class RegistrationView(generics.CreateAPIView):
def create(self, request, *args, **kwargs):
try:
- email_users = self.get_email_users(request.data.get('email'))
- for user in email_users:
+ email_field_name = get_user_email_field_name(User)
+ users = self.get_email_users(request.data.get(email_field_name))
+ for user in users:
serializer = self.get_serializer(instance=user)
- if settings.SEND_REREGISTRATION_EMAIL:
- self.send_reregistration_email(user)
+ if settings.RESEND_REGISTRATION_EMAIL:
+ self.resend_registration_email(user)
headers = self.get_success_headers(serializer.data)
- if not settings.REREGISTRATION_SHOW_RESPONSE and email_users:
+ if not settings.REGISTRATION_SHOW_EMAIL_FOUND and users:
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
except User.DoesNotExist:
pass
@@ -95,7 +96,7 @@ def send_confirmation_email(self, user):
email = email_factory.create()
email.send()
- def send_reregistration_email(self, user):
+ def resend_registration_email(self, user):
if user.is_active:
email_factory = utils.UserReregistrationEmailFactory.from_request(
self.request, user=user
diff --git a/docs/source/settings.rst b/docs/source/settings.rst
index a76bc4bb..87ee2fef 100644
--- a/docs/source/settings.rst
+++ b/docs/source/settings.rst
@@ -56,7 +56,7 @@ If ``True``, register or activation endpoint will send confirmation email to use
**Default**: ``False``
-SEND_REREGISTRATION_EMAIL
+RESEND_REGISTRATION_EMAIL
-------------------------
If ``True``, register endpoint will send warning and reminder email to user.
@@ -67,10 +67,10 @@ If User.is_active is False, will send a warning
**Default**: ``False``
-REREGISTRATION_SHOW_RESPONSE
+REGISTRATION_SHOW_EMAIL_FOUND
----------------------------
-If ``False`` (default), the ``/register/`` endpoint will always return
+If ``True`` (default), the ``/register/`` endpoint will always return
a ``HTTP_201_CREATED`` response, as well as the UserSerializer serializer.data response
of one of those users, so that it makes it difficult to distinguish if a User has this email