Skip to content
This repository has been archived by the owner on Oct 22, 2019. It is now read-only.

Signup redirect url parameter #530

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 6 additions & 1 deletion userena/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class SignupForm(forms.Form):
render_value=False),
label=_("Repeat password"))

def __init__(self, redirect=None, *args, **kwargs):
self.redirect = redirect
super(SignupForm, self).__init__(*args, **kwargs)

def clean_username(self):
"""
Validate that the username is alphanumeric and is not already in use.
Expand Down Expand Up @@ -94,7 +98,8 @@ def save(self):
email,
password,
not userena_settings.USERENA_ACTIVATION_REQUIRED,
userena_settings.USERENA_ACTIVATION_REQUIRED)
userena_settings.USERENA_ACTIVATION_REQUIRED,
redirect=self.redirect)
return new_user

class SignupFormOnlyEmail(SignupForm):
Expand Down
4 changes: 2 additions & 2 deletions userena/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class UserenaManager(UserManager):
""" Extra functionality for the Userena model. """

def create_user(self, username, email, password, active=False,
send_email=True):
send_email=True, redirect=None):
"""
A simple wrapper that creates a new :class:`User`.

Expand Down Expand Up @@ -78,7 +78,7 @@ def create_user(self, username, email, password, active=False,
userena_profile = self.create_userena_profile(new_user)

if send_email:
userena_profile.send_activation_email()
userena_profile.send_activation_email(redirect=redirect)

return new_user

Expand Down
7 changes: 4 additions & 3 deletions userena/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ def activation_key_expired(self):
return True
return False

def send_activation_email(self):
def send_activation_email(self, redirect=None):
"""
Sends a activation email to the user.

This email is send when the user wants to activate their newly created
This email is sent when the user wants to activate their newly created
user.

"""
Expand All @@ -169,7 +169,8 @@ def send_activation_email(self):
'protocol': get_protocol(),
'activation_days': userena_settings.USERENA_ACTIVATION_DAYS,
'activation_key': self.activation_key,
'site': Site.objects.get_current()}
'site': Site.objects.get_current(),
'redirect': redirect}

mailer = UserenaConfirmationMail(context=context)
mailer.generate_mail("activation")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{% blocktrans with site.name as site %}<p>Thank you for signing up at {{ site }}.</p>{% endblocktrans %}
<p>
{% trans "To activate your account you should click on the link below:" %}<br />
{{ protocol }}://{{ site.domain }}{% url 'userena_activate' activation_key %}
{{ protocol }}://{{ site.domain }}{% url 'userena_activate' activation_key %}{% if redirect %}?next={{redirect}}{% endif %}
</p>
<p>
{% trans "Thanks for using our site!" %}<br />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

{% trans "To activate your account you should click on the link below:" %}

{{ protocol }}://{{ site.domain }}{% url 'userena_activate' activation_key %}
{{ protocol }}://{{ site.domain }}{% url 'userena_activate' activation_key %}{% if redirect %}?next={{redirect}}{% endif %}

{% trans "Thanks for using our site!" %}

Expand Down
1 change: 1 addition & 0 deletions userena/templates/userena/signup_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@
{% endfor %}
</fieldset>
<input type="submit" value="{% trans "Signup"%}" />
{% if next %}<input type="hidden" name="next" value="{{ next }}" />{% endif %}
</form>
{% endblock %}
26 changes: 25 additions & 1 deletion userena/tests/tests_views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import re

from datetime import datetime, timedelta
from django.contrib.auth import get_user_model
from django.contrib.auth import get_user_model, REDIRECT_FIELD_NAME
from django.core.urlresolvers import reverse
from django.core import mail
from django.contrib.auth.forms import PasswordChangeForm
Expand Down Expand Up @@ -36,6 +36,30 @@ def test_valid_activation(self):
user = User.objects.get(email='alice@example.com')
self.assertTrue(user.is_active)

def test_activation_redirect(self):
""" A ``GET`` to the activation view with redirect parameter """

redirect = '/some/url/'

# First, register an account.
self.client.post('%s?%s=%s' % (reverse('userena_signup'), REDIRECT_FIELD_NAME, redirect),
data={'username': 'alice',
'email': 'alice@example.com',
'password1': 'swordfish',
'password2': 'swordfish',
'tos': 'on'})
user = User.objects.get(email='alice@example.com')

# Send a GET request with the redirect parameter to the url
response = self.client.get(
'%s?%s=%s' % (reverse('userena_activate', kwargs={'activation_key': user.userena_signup.activation_key}),
REDIRECT_FIELD_NAME, redirect))

self.assertTrue(response.get('Location').endswith(redirect))

if hasattr(response, 'url'):
self.assertTrue(response.url.endswith(redirect))

def test_activation_expired_retry(self):
""" A ``GET`` to the activation view when activation link is expired """
# First, register an account.
Expand Down
51 changes: 40 additions & 11 deletions userena/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.views import logout as Signout
from django.views.decorators.debug import sensitive_post_parameters
from django.views.generic import TemplateView
from django.views.generic.list import ListView
from django.contrib import messages
Expand Down Expand Up @@ -69,16 +70,19 @@ def get_queryset(self):
queryset = profile_model.objects.get_visible_profiles(self.request.user).select_related()
return queryset


@sensitive_post_parameters('password1', 'password2')
@secure_required
def signup(request, signup_form=SignupForm,
template_name='userena/signup_form.html', success_url=None,
extra_context=None):
extra_context=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Signup of an account.

Signup requiring a username, email and password. After signup a user gets
an email with an activation link used to activate their account. After
successful signup redirects to ``success_url``.
successful signup redirects to the ``REDIRECT_FIELD_NAME`` query parameter
if provided, otherwise ``success_url``.

:param signup_form:
Form that will be used to sign a user. Defaults to userena's
Expand All @@ -98,10 +102,16 @@ def signup(request, signup_form=SignupForm,
context. Defaults to a dictionary with a ``form`` key containing the
``signup_form``.

:param redirect_field_name:
String containing the name of the field that contains a redirect url.
Defaults to ``next``.

**Context**

``form``
Form supplied by ``signup_form``.
``next``
Next supplied by a query parameter.

"""
# If signup is disabled, return 403
Expand All @@ -115,16 +125,18 @@ def signup(request, signup_form=SignupForm,

form = signup_form()

redirect_url = request.GET.get(redirect_field_name, request.POST.get(redirect_field_name, None))

if request.method == 'POST':
form = signup_form(request.POST, request.FILES)
form = signup_form(redirect=redirect_url, data=request.POST, files=request.FILES)

if form.is_valid():
user = form.save()

# Send the signup complete signal
userena_signals.signup_complete.send(sender=None,
user=user)


if success_url: redirect_to = success_url
else: redirect_to = reverse('userena_signup_complete',
kwargs={'username': user.username})
Expand All @@ -138,28 +150,38 @@ def signup(request, signup_form=SignupForm,
user = authenticate(identification=user.email, check_password=False)
login(request, user)

# since we signed in the user and have no more information to display,
# we can redirect the user to a requested page
if redirect_url:
redirect_to = redirect_url

return redirect(redirect_to)

if not extra_context: extra_context = dict()
extra_context['form'] = form
extra_context.update({
'form': form,
'next': redirect_url,
})
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)

@secure_required
def activate(request, activation_key,
template_name='userena/activate_fail.html',
retry_template_name='userena/activate_retry.html',
success_url=None, extra_context=None):
success_url=None, extra_context=None,
redirect_field_name=REDIRECT_FIELD_NAME):
"""
Activate a user with an activation key.

The key is a SHA1 string. When the SHA1 is found with an
:class:`UserenaSignup`, the :class:`User` of that account will be
activated. After a successful activation the view will redirect to
``success_url``. If the SHA1 is not found, the user will be shown the
``template_name`` template displaying a fail message.
If the SHA1 is found but expired, ``retry_template_name`` is used instead,
so the user can proceed to :func:`activate_retry` to get a new activation key.
the ``REDIRECT_FIELD_NAME`` query parameter if provided, otherwise
``success_url``. If the SHA1 is not found, the user will be shown the
``template_name`` template displaying a fail message. If the SHA1 is found
but expired, ``retry_template_name`` is used instead, so the user can
proceed to :func:`activate_retry` to get a new activation key.

:param activation_key:
String of a SHA1 string of 40 characters long. A SHA1 is always 160bit
Expand Down Expand Up @@ -201,7 +223,10 @@ def activate(request, activation_key,
messages.success(request, _('Your account has been activated and you have been signed in.'),
fail_silently=True)

if success_url: redirect_to = success_url % {'username': user.username }
redirect_to = request.GET.get(redirect_field_name, None)

if redirect_to: pass
elif success_url: redirect_to = success_url % {'username': user.username }
else: redirect_to = reverse('userena_profile_detail',
kwargs={'username': user.username})
return redirect(redirect_to)
Expand Down Expand Up @@ -386,6 +411,8 @@ def disabled_account(request, username, template_name, extra_context=None):
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)


@sensitive_post_parameters('password')
@secure_required
def signin(request, auth_form=AuthenticationForm,
template_name='userena/signin_form.html',
Expand Down Expand Up @@ -563,6 +590,8 @@ def email_change(request, username, email_form=ChangeEmailForm,
return ExtraContextTemplateView.as_view(template_name=template_name,
extra_context=extra_context)(request)


@sensitive_post_parameters('old_password', 'new_password1', 'new_password2')
@secure_required
@permission_required_or_403('change_user', (get_user_model(), 'username', 'username'))
def password_change(request, username, template_name='userena/password_form.html',
Expand Down