Skip to content
Merged
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
40 changes: 38 additions & 2 deletions user_management/api/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
import re

from django.contrib.auth import get_user_model
from django.contrib.auth import get_user_model, signals
from django.contrib.auth.hashers import check_password
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.models import Site
Expand All @@ -11,7 +11,7 @@
from django.utils import timezone
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from mock import patch
from mock import MagicMock, patch
from rest_framework import status
from rest_framework.test import APIRequestFactory

Expand Down Expand Up @@ -54,6 +54,17 @@ def test_post(self):
token = self.model.objects.get()
self.assertEqual(response.data['token'], token.key)

def test_post_last_login_updates(self):
"""Authenticating updates the user's last_login."""
user = UserFactory.create(email=self.username, password=self.password)
now = timezone.now()
self.assertLess(user.last_login, now)

request = self.create_request('post', auth=False, data=self.data)
self.view_class.as_view()(request)
user = User.objects.get(pk=user.pk)
self.assertGreater(user.last_login, now)

def test_post_non_existing_user(self):
"""Assert non existing raises an error."""
request = self.create_request('post', auth=False, data=self.data)
Expand Down Expand Up @@ -118,6 +129,31 @@ def test_delete(self):
with self.assertRaises(self.model.DoesNotExist):
self.model.objects.get(pk=token.pk)

def test_delete_user_logged_out_signal(self):
"""Send the user_logged_out signal if a user deletes their Auth Token."""
handler = MagicMock()
signals.user_logged_out.connect(handler)

someday = timezone.now() + datetime.timedelta(days=1)
user = UserFactory.create()
token = AuthTokenFactory.create(user=user, expires=someday)

# Custom auth header containing token
auth = 'Token ' + token.key
request = self.create_request(
'delete',
user=user,
HTTP_AUTHORIZATION=auth,
)
response = self.view_class.as_view()(request)

handler.assert_called_once_with(
signal=signals.user_logged_out,
sender=views.GetAuthToken,
request=response.renderer_context['request'],
user=user,
)

def test_delete_no_token(self):
request = self.create_request('delete')
response = self.view_class.as_view()(request)
Expand Down
11 changes: 9 additions & 2 deletions user_management/api/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.contrib.auth import get_user_model
from django.contrib.auth import get_user_model, signals
from django.contrib.auth.tokens import default_token_generator
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
Expand Down Expand Up @@ -36,7 +36,9 @@ def post(self, request):
but not re-using them."""
serializer = self.serializer_class(data=request.DATA)
if serializer.is_valid():
token = self.model.objects.create(user=serializer.object['user'])
user = serializer.object['user']
signals.user_logged_in.send(type(self), user=user, request=request)
token = self.model.objects.create(user=user)
token.update_expiry()
return response.Response({'token': token.key})

Expand Down Expand Up @@ -64,6 +66,11 @@ def delete(self, request, *args, **kwargs):
pass
else:
token.delete()
signals.user_logged_out.send(
type(self),
user=token.user,
request=request,
)
return response.Response(status=status.HTTP_204_NO_CONTENT)


Expand Down