diff --git a/userena/managers.py b/userena/managers.py index ee8c48f6..c6400b31 100644 --- a/userena/managers.py +++ b/userena/managers.py @@ -103,6 +103,30 @@ def create_userena_profile(self, user): return self.create(user=user, activation_key=activation_key) + def reissue_activation(self, activation_key): + """ + Creates a new ``activation_key`` resetting activation timeframe when + users let the previous key expire. + + :param activation_key: + String containing the secret SHA1 activation key. + + """ + try: + userena = self.get(activation_key=activation_key) + except self.model.DoesNotExist: + return False + try: + salt, new_activation_key = generate_sha1(userena.user.username) + userena.activation_key = new_activation_key + userena.save(using=self._db) + userena.user.date_joined = get_datetime_now() + userena.user.save(using=self._db) + userena.send_activation_email() + return True + except Exception,e: + return False + def activate_user(self, activation_key): """ Activate an :class:`User` by supplying a valid ``activation_key``. @@ -136,6 +160,25 @@ def activate_user(self, activation_key): return user return False + def check_expired_activation(self, activation_key): + """ + Check if ``activation_key`` is still valid. + + Raises a ``self.model.DoesNotExist`` exception if key is not present or + ``activation_key`` is not a valid string + + :param activation_key: + String containing the secret SHA1 for a valid activation. + + :return: + True if the ket has expired, False if still valid. + + """ + if SHA1_RE.search(activation_key): + userena = self.get(activation_key=activation_key) + return userena.activation_key_expired() + raise self.model.DoesNotExist + def confirm_email(self, confirmation_key): """ Confirm an email address by checking a ``confirmation_key``. diff --git a/userena/settings.py b/userena/settings.py index 8df4b80c..da6e394c 100644 --- a/userena/settings.py +++ b/userena/settings.py @@ -34,6 +34,10 @@ 'USERENA_ACTIVATION_NOTIFY_DAYS', 5) +USERENA_ACTIVATION_RETRY = getattr(settings, + 'USERENA_ACTIVATION_RETRY', + False) + USERENA_ACTIVATED = getattr(settings, 'USERENA_ACTIVATED', 'ALREADY_ACTIVATED') diff --git a/userena/templates/userena/activate_retry.html b/userena/templates/userena/activate_retry.html new file mode 100644 index 00000000..dbdf55d7 --- /dev/null +++ b/userena/templates/userena/activate_retry.html @@ -0,0 +1,12 @@ +{% extends 'userena/base_userena.html' %} +{% load i18n %} +{% load url from future %} + + +{% block title %}{% trans "Account activation failed." %}{% endblock %} +{% block content_title %}
{% trans "Your account could not be activated because activation link is expired." %}
+{% trans "Request a new activation link." %}
+{% endblock %} diff --git a/userena/templates/userena/activate_retry_success.html b/userena/templates/userena/activate_retry_success.html new file mode 100644 index 00000000..5ee3a0f2 --- /dev/null +++ b/userena/templates/userena/activate_retry_success.html @@ -0,0 +1,13 @@ +{% extends 'userena/base_userena.html' %} +{% load i18n %} +{% load url from future %} + + +{% block title %}{% trans "Account re-activation succeded." %}{% endblock %} +{% block content_title %}{% blocktrans %}You requested a new activation of your account..{% endblocktrans %}
+{% blocktrans %}You have been sent an e-mail with an activation link to the supplied email.{% endblocktrans %}
+{% blocktrans %}We will store your signup information for {{ userena_activation_days }} days on our server. {% endblocktrans %}
+{% endblock %} diff --git a/userena/tests/views.py b/userena/tests/views.py index ad684c4b..155435ac 100644 --- a/userena/tests/views.py +++ b/userena/tests/views.py @@ -1,7 +1,9 @@ +from datetime import datetime, timedelta from django.core.urlresolvers import reverse from django.core import mail from django.contrib.auth.forms import PasswordChangeForm from django.conf import settings +from django.test.utils import override_settings from userena import forms from userena import settings as userena_settings @@ -33,6 +35,65 @@ def test_valid_activation(self): user = User.objects.get(email='alice@example.com') self.failUnless(user.is_active) + def test_activation_expired_retry(self): + """ A ``GET`` to the activation view when activation link is expired """ + # First, register an account. + userena_settings.USERENA_ACTIVATION_RETRY = True + self.client.post(reverse('userena_signup'), + data={'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'swordfish', + 'password2': 'swordfish', + 'tos': 'on'}) + user = User.objects.get(email='alice@example.com') + user.date_joined = datetime.today() - timedelta(days=30) + user.save() + response = self.client.get(reverse('userena_activate', + kwargs={'activation_key': user.userena_signup.activation_key})) + self.assertContains(response, "Request a new activation link") + + user = User.objects.get(email='alice@example.com') + self.failUnless(not user.is_active) + userena_settings.USERENA_ACTIVATION_RETRY = False + + def test_retry_activation_ask(self): + """ Ask for a new activation link """ + # First, register an account. + userena_settings.USERENA_ACTIVATION_RETRY = True + self.client.post(reverse('userena_signup'), + data={'username': 'alice', + 'email': 'alice@example.com', + 'password1': 'swordfish', + 'password2': 'swordfish', + 'tos': 'on'}) + user = User.objects.get(email='alice@example.com') + user.date_joined = datetime.today() - timedelta(days=30) + user.save() + old_key = user.userena_signup.activation_key + response = self.client.get(reverse('userena_activate_retry', + kwargs={'activation_key': old_key})) + + # We must reload the object from database to get the new key + user = User.objects.get(email='alice@example.com') + self.assertContains(response, "Account re-activation succeded") + + self.failIfEqual(old_key, user.userena_signup.activation_key) + user = User.objects.get(email='alice@example.com') + self.failUnless(not user.is_active) + + self.failUnlessEqual(len(mail.outbox), 2) + self.assertEqual(mail.outbox[1].to, ['alice@example.com']) + self.assertTrue(mail.outbox[1].body.find("activate your account ")>-1) + + response = self.client.get(reverse('userena_activate', + kwargs={'activation_key': user.userena_signup.activation_key})) + self.assertRedirects(response, + reverse('userena_profile_detail', kwargs={'username': user.username})) + + user = User.objects.get(email='alice@example.com') + self.failUnless(user.is_active) + userena_settings.USERENA_ACTIVATION_RETRY = False + def test_invalid_activation(self): """ A ``GET`` to the activation view with a wrong ``activation_key``. diff --git a/userena/urls.py b/userena/urls.py index 13457c06..c7d7a2c6 100644 --- a/userena/urls.py +++ b/userena/urls.py @@ -49,6 +49,11 @@ userena_views.activate, name='userena_activate'), + # Retry activation + url(r'^activate/retry/(?P