Commit 132afbf8 authored by Jannis Leidel's avatar Jannis Leidel
Browse files

Fixed #5612 -- Added login and logout signals to contrib auth app. Thanks SmileyChris and pterk.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14710 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 81323cb1
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ import datetime
from warnings import warn
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
from django.contrib.auth.signals import user_logged_in, user_logged_out

SESSION_KEY = '_auth_user_id'
BACKEND_SESSION_KEY = '_auth_user_backend'
@@ -62,8 +63,7 @@ def login(request, user):
    if user is None:
        user = request.user
    # TODO: It would be nice to support different login methods, like signed cookies.
    user.last_login = datetime.datetime.now()
    user.save()
    user_logged_in.send(sender=user.__class__, request=request, user=user)

    if SESSION_KEY in request.session:
        if request.session[SESSION_KEY] != user.id:
@@ -83,6 +83,13 @@ def logout(request):
    Removes the authenticated user's ID from the request and flushes their
    session data.
    """
    # Dispatch the signal before the user is logged out so the receivers have a
    # chance to find out *who* logged out.
    user = getattr(request, 'user', None)
    if hasattr(user, 'is_authenticated') and not user.is_authenticated():
        user = None
    user_logged_out.send(sender=user.__class__, request=request, user=user)

    request.session.flush()
    if hasattr(request, 'user'):
        from django.contrib.auth.models import AnonymousUser
+10 −0
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@ import datetime
import urllib

from django.contrib import auth
from django.contrib.auth.signals import user_logged_in
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.db.models.manager import EmptyManager
@@ -40,6 +41,15 @@ def check_password(raw_password, enc_password):
    algo, salt, hsh = enc_password.split('$')
    return hsh == get_hexdigest(algo, salt, raw_password)

def update_last_login(sender, user, **kwargs):
    """
    A signal receiver which updates the last_login date for
    the user logging in.
    """
    user.last_login = datetime.datetime.now()
    user.save()
user_logged_in.connect(update_last_login)

class SiteProfileNotAvailable(Exception):
    pass

+4 −0
Original line number Diff line number Diff line
from django.dispatch import Signal

user_logged_in = Signal(providing_args=['request', 'user'])
user_logged_out = Signal(providing_args=['request', 'user'])
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ from django.contrib.auth.tests.forms import UserCreationFormTest, Authentication
from django.contrib.auth.tests.remote_user \
        import RemoteUserTest, RemoteUserNoCreateTest, RemoteUserCustomTest
from django.contrib.auth.tests.models import ProfileTestCase
from django.contrib.auth.tests.signals import SignalTestCase
from django.contrib.auth.tests.tokens import TokenGeneratorTest
from django.contrib.auth.tests.views \
        import PasswordResetTest, ChangePasswordTest, LoginTest, LogoutTest
+47 −0
Original line number Diff line number Diff line
from django.test import TestCase
from django.contrib.auth import signals


class SignalTestCase(TestCase):
    urls = 'django.contrib.auth.tests.urls'
    fixtures = ['authtestdata.json']

    def listener_login(self, user, **kwargs):
        self.logged_in.append(user)

    def listener_logout(self, user, **kwargs):
        self.logged_out.append(user)

    def setUp(self):
        """Set up the listeners and reset the logged in/logged out counters"""
        self.logged_in = []
        self.logged_out = []
        signals.user_logged_in.connect(self.listener_login)
        signals.user_logged_out.connect(self.listener_logout)

    def tearDown(self):
        """Disconnect the listeners"""
        signals.user_logged_in.disconnect(self.listener_login)
        signals.user_logged_out.disconnect(self.listener_logout)

    def test_login(self):
        # Only a successful login will trigger the signal.
        self.client.login(username='testclient', password='bad')
        self.assertEqual(len(self.logged_in), 0)
        # Like this:
        self.client.login(username='testclient', password='password')
        self.assertEqual(len(self.logged_in), 1)
        self.assertEqual(self.logged_in[0].username, 'testclient')

    def test_logout_anonymous(self):
        # The log_out function will still trigger the signal for anonymous
        # users.
        self.client.get('/logout/next_page/')
        self.assertEqual(len(self.logged_out), 1)
        self.assertEqual(self.logged_out[0], None)

    def test_logout(self):
        self.client.login(username='testclient', password='password')
        self.client.get('/logout/next_page/')
        self.assertEqual(len(self.logged_out), 1)
        self.assertEqual(self.logged_out[0].username, 'testclient')
Loading