Commits

James Bennett committed ec5ec67

Somewhat large-ish change: activate view now always returns a redirect (to a backend-specific location) on success.

Comments (0)

Files changed (7)

docs/backend-api.rst

 a full implementation is needed.
 
 
-register(self, request, \*\*kwargs)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+register(request, \*\*kwargs)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 This method implements the logic of actually creating the new user
 account. Often, but not necessarily always, this will involve creating
 Finally, this method should return the ``User`` instance.
 
 
-activate(self, request, \*\*kwargs)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+activate(request, \*\*kwargs)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 For workflows which require a separate activation step, this method
 should implement the necessary logic for account activation.
 method can and should raise ``NotImplementedError``.
 
 
-registration_allowed(self, request)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+registration_allowed(request)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 This method returns a boolean value indicating whether the given
 ``HttpRequest`` is permitted to register a new account (``True`` if
 explaining that registration is not permitted.
 
 
-get_form_class(self, request)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+get_form_class(request)
+~~~~~~~~~~~~~~~~~~~~~~~
 
 This method should return a form class -- a subclass of
 ``django.forms.Form`` -- suitable for use in registering users with
     attempting to register.
 
 
-post_registration_redirect(self, request, user)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+post_registration_redirect(request, user)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 This method should return a location to which the user will be
 redirected after successful registration. This should be a tuple of
 
 ``user``
     The ``User`` instance representing the new user account.
+
+
+post_activation_redirect(request, user)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For workflows which require a separate activation step, this method
+should return a location to which the user will be redirected after
+successful activation.  This should be a tuple of ``(to, args,
+kwargs)``, suitable for use as the arguments to `Django's "redirect"
+shortcut
+<http://docs.djangoproject.com/en/dev/topics/http/shortcuts/#redirect>`_.
+
+Arguments to this method are:
+
+``request``
+    The Django ``HttpRequest`` object in which the user activated.
+
+``user``
+    The ``User`` instance representing the activated user account.
+
+For workflows which do not require a separate activation step, this
+method can and should raise ``NotImplementedError``.
 django-registration provides two views. Both are designed to allow
 easy configurability without writing or rewriting view code.
 
-.. function:: activate(request, backend, template_name='registration/activate.html', extra_context=None, **kwargs)
+.. function:: activate(request, backend, template_name='registration/activate.html', success_url=None, extra_context=None, **kwargs)
 
    Activate a user's account, for workflows which require a separate
    activation step.
    successful, or a value which evaluates to ``False`` in boolean
    context if not.
 
+   Upon successful activation, the backend's
+   ``post_activation_redirect()`` method will be called, passing the
+   ``HttpRequest`` and the activated ``User`` to determine the URL to
+   redirect the user to. To override this, pass the argument
+   ``success_url`` (see below).
+
+   On unsuccessful activation, will render the template
+   ``registration/activate.html`` to display an error message; to
+   override thise, pass the argument ``template_name`` (see below).
+
    **Context**
 
-   ``account``
-      A ``User`` object representing the activated account, if the
-      activation was successful. ``False`` if the activation was not
-      successful.
-
-   This view uses ``RequestContext``, so variables populated by
-   context processors will also be present in the context.
+   The context will be populated from the keyword arguments captured
+   in the URL. This view uses ``RequestContext``, so variables
+   populated by context processors will also be present in the
+   context.
 
    :param backend: A string containing the dotted Python path to the
       backend class to use.
-   :param template_name: Optional. A custom template name to use. If
-      not specified, this will default to
-      ``registration/activate.html``.
    :param extra_context: Optional. A dictionary of variables to add to
       the template context. Any callable object in this dictionary
       will be called to produce the final result which appears in the
       context.
+   :param template_name: Optional. A custom template name to use. If
+      not specified, this will default to
+      ``registration/activate.html``.
    :param **kwargs: Any keyword arguments captured from the URL, such
       as an activation key, which will be passed to the backend's
       ``activate()`` method.
 
    :param backend: A string containing the dotted Python path to the
       backend class to use.
+   :param disallowed_url: The URL to redirect to if registration is
+      not permitted (e.g., if registration is closed). This should be
+      a string suitable for passing as the ``to`` argument to
+      `Django's "redirect" shortcut
+      <http://docs.djangoproject.com/en/dev/topics/http/shortcuts/#redirect>`_. If
+      not specified, this will default to ``registration_disallowed``.
+   :param extra_context: Optional. A dictionary of variables to add to
+      the template context. Any callable object in this dictionary
+      will be called to produce the final result which appears in the
+      context.
+   :param form_classs: The form class to use for registration; this
+      should be some subclass of ``django.forms.Form``. If not
+      specified, the backend's ``get_form_class()`` method will be
+      called to obtain the form class.
    :param success_url: The URL to redirect to after successful
       registration. This should be a string suitable for passing as
       the ``to`` argument to `Django's "redirect" shortcut
       <http://docs.djangoproject.com/en/dev/topics/http/shortcuts/#redirect>`_. If
       not specified, the backend's ``post_registration_redirect()``
       method will be called to obtain the URL.
-   :param form_classs: The form class to use for registration; this
-      should be some subclass of ``django.forms.Form``. If not
-      specified, the backend's ``get_form_class()`` method will be
-      called to obtain the form class.
-   :param disallowed_url: The URL to redirect to if registration is
-      not permitted (e.g., if registration is closed). This should be
-      a string suitable for passing as the ``to`` argument to
-      `Django's "redirect" shortcut
-      <http://docs.djangoproject.com/en/dev/topics/http/shortcuts/#redirect>`_. If
-      not specified, this will default to ``registration_disallowed``.
    :param template_name: Optional. A custom template name to use. If
       not specified, this will default to
       ``registration/registration_form.html``.
-   :param extra_context: Optional. A dictionary of variables to add to
-      the template context. Any callable object in this dictionary
-      will be called to produce the final result which appears in the
-      context.

registration/backends/default/__init__.py

         
         """
         return ('registration_complete', (), {})
+
+    def post_activation_redirect(self, request, user):
+        """
+        Return the name of the URL to redirect to after successful
+        account activation.
+        
+        """
+        return ('registration_activation_complete', (), {})

registration/backends/default/urls.py

 
 
 urlpatterns = patterns('',
+                       url(r'^activate/complete/$',
+                           direct_to_template,
+                           { 'template': 'registration/activation_complete.html' },
+                           name='registration_activation_complete'),
                        # Activation keys get matched by \w+ instead of the more specific
                        # [a-fA-F0-9]{40} because a bad activation key should still get to the view;
                        # that way it can return a sensible "invalid key" message instead of a

registration/tests/urls.py

                            {'extra_context': {'foo': 'bar', 'callable': lambda: 'called'},
                             'backend': 'registration.backends.default.DefaultBackend'},
                            name='registration_test_activate_extra_context'),
-                       (r'', include('registration.backends.default.urls')),
+                       # Test the 'activate' view with success_url argument.
+                       url(r'^activate-with-success-url/(?P<activation_key>\w+)/$',
+                           activate,
+                           {'success_url': 'registration_test_custom_success_url',
+                            'backend': 'registration.backends.default.DefaultBackend'},
+                           name='registration_test_activate_success_url'),
                        # Test the 'register' view with custom template
                        # name.
                        url(r'^register-with-template-name/$',
                            direct_to_template,
                            {'template': 'registration/test_template_name.html'},
                            name='registration_test_custom_success_url'),
+                       (r'', include('registration.backends.default.urls')),
                        )

registration/tests/views.py

         activation window).
 
         """
+        success_redirect = 'http://testserver%s' % reverse('registration_activation_complete')
+        
         # First, register an account.
         self.client.post(reverse('registration_register'),
                          data={'username': 'alice',
                                'password1': 'swordfish',
                                'password2': 'swordfish'})
         profile = RegistrationProfile.objects.get(user__username='alice')
-
         response = self.client.get(reverse('registration_activate',
                                            kwargs={'activation_key': profile.activation_key}))
-        self.assertEqual(response.status_code, 200)
-        self.assertTemplateUsed(response,
-                                'registration/activate.html')
-        self.failUnless(isinstance(response.context['account'],
-                                   User))
-        self.assertEqual(response.context['account'].username,
-                         u'alice')
+        self.assertRedirects(response, success_redirect)
         self.failUnless(User.objects.get(username='alice').is_active)
 
     def test_invalid_activation(self):
         response = self.client.get(reverse('registration_activate',
                                            kwargs={'activation_key': expired_profile.activation_key}))
         self.assertEqual(response.status_code, 200)
-        self.failIf(response.context['account'])
+        self.assertEqual(response.context['activation_key'],
+                         expired_profile.activation_key)
         self.failIf(User.objects.get(username='bob').is_active)
 
+    def test_activation_success_url(self):
+        """
+        Passing ``success_url`` to the ``activate`` view and
+        successfully activating will result in that URL being used for
+        the redirect.
+        
+        """
+        success_redirect = 'http://testserver%s' % reverse('registration_test_custom_success_url')
+        self.client.post(reverse('registration_register'),
+                         data={'username': 'alice',
+                               'email': 'alice@example.com',
+                               'password1': 'swordfish',
+                               'password2': 'swordfish'})
+        profile = RegistrationProfile.objects.get(user__username='alice')
+        response = self.client.get(reverse('registration_test_activate_success_url',
+                                           kwargs={'activation_key': profile.activation_key}))
+        self.assertRedirects(response, success_redirect)
+        
     def test_activation_template_name(self):
         """
         Passing ``template_name`` to the ``activate`` view will result

registration/views.py

 
 def activate(request, backend,
              template_name='registration/activate.html',
-             extra_context=None, **kwargs):
+             success_url=None, extra_context=None, **kwargs):
     """
     Activate a user's account.
 
     return a ``User`` if activation was successful, or a value which
     evaluates to ``False`` in boolean context if not.
 
-    **Optional arguments**
+    Upon successful activation, the backend's
+    ``post_activation_redirect()`` method will be called, passing the
+    ``HttpRequest`` and the activated ``User`` to determine the URL to
+    redirect the user to. To override this, pass the argument
+    ``success_url`` (see below).
+
+    On unsuccessful activation, will render the template
+    ``registration/activate.html`` to display an error message; to
+    override thise, pass the argument ``template_name`` (see below).
+
+    **Arguments**
 
     ``backend``
-        The dotted Python import path to the backend class to use.
+        The dotted Python import path to the backend class to
+        use. Required.
 
     ``extra_context``
         A dictionary of variables to add to the template context. Any
         callable object in this dictionary will be called to produce
-        the end result which appears in the context.
+        the end result which appears in the context. Optional.
+
+    ``success_url``
+        The name of a URL pattern to redirect to on successful
+        acivation. This is optional; if not specified, this will be
+        obtained by calling the backend's
+        ``post_activation_redirect()`` method.
     
     ``template_name``
-        A custom template to use. If not specified, this will default
-        to ``registration/activate.html``.
+        A custom template to use. This is optional; if not specified,
+        this will default to ``registration/activate.html``.
+
+    ``\*\*kwargs``
+        Any keyword arguments captured from the URL, such as an
+        activation key, which will be passed to the backend's
+        ``activate()`` method.
     
     **Context:**
     
-    ``account``
-        The ``User`` object corresponding to the account, if the
-        activation was successful. ``False`` if the activation was not
-        successful.
-    
-    Any extra variables supplied in the ``extra_context`` argument
-    (see above).
+    The context will be populated from the keyword arguments captured
+    in the URL, and any extra variables supplied in the
+    ``extra_context`` argument (see above).
     
     **Template:**
     
     """
     backend = get_backend(backend)
     account = backend.activate(request, **kwargs)
+    if account:
+        if success_url is None:
+            to, args, kwargs = backend.post_activation_redirect(request, account)
+            return redirect(to, *args, **kwargs)
+        else:
+            return redirect(success_url)
     if extra_context is None:
         extra_context = {}
     context = RequestContext(request)
     for key, value in extra_context.items():
         context[key] = callable(value) and value() or value
     return render_to_response(template_name,
-                              { 'account': account, },
+                              kwargs,
                               context_instance=context)
 
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.